How to access Physics World in Layer - cocos2d-x

I need to create joint between two bodies in layer. Joints are to be added in physics world. How can i access physics world in layer?

My JavaScript implementation. Hope it will help.
var space;
function initPhysics() {
space = new cp.Space();
space.gravity = cp.v(0, -800);
space.iterations = 30;
space.sleepTimeThreshold = Infinity;
space.collisionSlop = Infinity;
}
function addJoints() {
chainTableJoint1 = new cp.PivotJoint(chainEnd1, tableBackBody, cp.v.add(cp.v(chainEnd1.getPos().x, tableBackNode.getPosition().y + (tableBackNode.getContentSize().height * 0.5)), boxOffset));
chainTableJoint2 = new cp.PivotJoint(chainEnd2, tableBackBody, cp.v.add(cp.v(chainEnd2.getPos().x, tableBackNode.getPosition().y + (tableBackNode.getContentSize().height * 0.5)), boxOffset));
space.addConstraint(chainTableJoint1);
space.addConstraint(chainTableJoint2);
}

you have four options:
1)- override Layer::onEnter() or onEnterTransitionDidFinish ()
methods then access from theme like this:
Layer::onEnter(){
Layer::onEnter();
auto world = _director->getRunningScene()->getPhysicsWorld();
}
2)- create a custom Layer::createScene() method then access from Layer::init() like this:
Scene* GameScene::createScene()
{
auto layer = new (std::nothrow) GameScene;
if (layer)
{
auto scene = Scene::createWithPhysics();
layer->autorelease();
scene->addChild(layer);
if (layer->init()) return scene;
}
CC_SAFE_DELETE(layer);
return nullptr;
}
// then in Layer::init() you do this:
Layer::init(){
auto world = _director->getRunningScene()->getPhysicsWorld();
}
3)- add a PhysicsWorld getter method to the director (involves some library code customization's):
first go to CCDirector.h and then add a forward declaration of the scene class under NS_CC_BEGIN like this:
NS_CC_BEGIN
class cocos2d::Scene;
then go to the private section of the Director class and add these two lines like this:
private:
cocos2d::PhysicsWorld* _myPhysicsWorld;
friend class Scene;
then go to the public section of the Director class and add this getter method like this:
public:
cocos2d::PhysicsWorld* getWorld() const{
return _myPhysicsWorld;
};
this is an overview of the changes made in CCDirector.h file:
// CCDirector.h
NS_CC_BEGIN
// 1
class cocos2d::Scene;
class Director : public Ref{
public:
//2
cocos2d::PhysicsWorld* getWorld() const{
return _myPhysicsWorld;
};
private:
// 3
cocos2d::PhysicsWorld* _myPhysicsWorld;
friend class cocos2d::Scene;
};
NS_CC_END
so after that we go to CCScene.cpp into a method with this signature (bool Scene::initWithPhysics()) in it you will find a call to PhysicsWorld::construct(this) add just right after that method call this line:
_director->_myPhysicsWorld = _physicsWorld;
and this should be the overview of what we did in CCScene.cpp:
// CCScene.cpp
class Scene : public Node{
bool Scene::initWithPhysics(){
_physicsWorld = PhysicsWorld::construct(this);
// 4 since Director is a singleton class, we can access its instance from anywhere
_director->_myPhysicsWorld = _physicsWorld;
}
};
now as soon as Scene::createWithPhysics() gets called anywhere the director will get a copy of the PhysicsWorld pointer which can be accessed using our director getWorld() method anywhere anytime!! (because the director is a singleton as you know) and thats all without exposing _myPhysicsWorld to the user meaning he can only read _myPhysicsWorld from the outside!!
4)- make your own Custom PhysicsWorld class and since PhysicsWorld::construct() is protected which means it can be easily inherited.
// PhysicsManager.h
class PhysicsManager : public cocos2d::PhysicsWorld
{
public:
static PhysicsManager* createWorld(cocos2d::Scene* scene) {
_myPhysicsWorld = PhysicsWorld::construct(scene);
}
PhysicsWorld* getWorld() const { return _myPhysicsWorld; }
private:
static cocos2d::PhysicsWorld* _myPhysicsWorld;
};
//PhysicsManager.cpp
PhysicsManager::PhysicsWorld* _myPhysicsWorld;
now you can use it like this:
Layer::init(){
auto physicsManager = PhysicsManager::createWorld(this->getScene());
auto world = physicsManager->getWorld();
}
remember that you can even make it a singleton class if you want to!
Edit:
I forgot to mention that there is another good solution in here:
http://discuss.cocos2d-x.org/t/physics-joint-distance-problem/17926/2

Related

AS3 - Problems with IExternalizable

So, i've been working with ByteArrays a lot recently and i'm running into some annoying problems that make me want to rip my hair out.
basically, i'm trying to save project data for an application that i'm making to compile characters for a game into one file. the project consists of custom objects, vectors, vectors of vectors, and even vectors of vectors of custom objects! i figured the best way to write all this data properly would be to use the IExternalizable interface with the readExternal and writeExternal commands. so here's what i'm doing.
i write all the project data to an object, then write that object into a ByteArray, and save it to a file:
// probject means project object !
mProbject= { };
// Register vector as class, just to prevent any errors about that just in case
registerClassAlias("vec_core.timeline.KeyFrame", Vector.<KeyFrame> as Class);
// single KeyFrame Object
mProbject.currentFrame = Main.getInstance().animationList.selectedItem.currentKeyFrame;
// a Vector.<Vector.<KeyFrame>>
mProbject.frames = Main.getInstance().animationList.keyFrameVectorVector;
// an unsigned int
mProbject.selectedItemIndex = Main.getInstance().animationList.entries.indexOf(Main.getInstance().animationList.selectedItem);
// Vector.<String>
mProbject.animationNames = Main.getInstance().animationList.animationNames;
// String
mProbject.projectPath = nativePath;
//String
mProbject.projectName = name;
mByteArray = new ByteArray();
mByteArray.writeObject(mProbject);
mByteArray.compress();
return mByteArray;
inside the KeyFrame class though, there is two more vectors of custom objects:
private var mHitboxes:Vector.<Hitbox>;
private var mHitboxSprites:Vector.<HitboxSprite>;
so i set up both of those classes and my KeyFrame class to use IExternalizable:
public class HitboxSprite extends Sprite implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
trueBounds.x = input.readFloat();
trueBounds.y = input.readFloat();
trueBounds.width = input.readFloat();
trueBounds.height = input.readFloat();
mHitbox = input.readObject();
}
public function writeExternal(output:IDataOutput):void
{
output.writeFloat(trueBounds.x);
output.writeFloat(trueBounds.y);
output.writeFloat(trueBounds.width);
output.writeFloat(trueBounds.height);
output.writeObject(mHitbox);
}
}
public class Hitbox implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mName = input.readUTF();
mType = input.readUnsignedInt();
mEnabled = input.readBoolean();
mKnockback = input.readBoolean();
x = input.readFloat();
y = input.readFloat();
width = input.readFloat();
height = input.readFloat();
addMultipleTags(input.readUTF());
}
public function writeExternal(output:IDataOutput):void
{
output.writeUTF(mName);
output.writeUnsignedInt(mType);
output.writeBoolean(mEnabled);
output.writeBoolean(mKnockback);
output.writeFloat(mX);
output.writeFloat(mY);
output.writeFloat(mWidth);
output.writeFloat(mHeight);
output.writeUTF(getAllTags());
}
}
public class KeyFrame implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mID = input.readUnsignedInt();
mLabel = input.readUTF();
}
public function writeExternal(output:IDataOutput):void
{
output.writeUnsignedInt(mID);
output.writeUTF(mLabel);
}
}
but when it gets to the writeObject() method of the "root" ByteArray, i get the error:
[Fault] exception, information=ArgumentError: Error #2004: One of the parameters is invalid.
this is probably the single most annoying problem i've ever had. it seems like i've tried everything and nothing is working.
does anyone else have experience with this? am i doing something wrong??
i'd appreciate any help i can get on this. i just wanna continue making my game :<
Like mentioned in the comment section, you were looking for this. What rang the bell for me was the "Sprite" class you extended. That made me suspicious in the matter that you were trying to externalize visualizable content.

Get stage in ActionScript-3 without a DisplayObject?

How can I get a reference to my stage without having a Sprite/DisplayObject that is added to the stage already ?
More info: I have a static class that is a utility class and I want it to initialize in static class constructor but I also need the reference to the stage.
public class UtilClass
{
trace("init: " + stage);
}
First thing that is called in my AS-3 apps is the constructor of my main Sprite/DisplayObject and it has access to the stage. So the stage exists at that point. Then I call utility methods of my UtilClass. Now I want it to initialize by itself on the first use (when stage is already in existance).
I want to know if stage object can be accessed from anywhere without being initialized from outside of the utility class.
Edit:
public class SimpleSprite extends Sprite
{
public static var aaa:int = 12;
public static function test():void
{
trace("here I am");
}
trace(aaa, Capabilities.screenResolutionX+", "+Capabilities.screenResolutionY);
test();
}
The stage reference is available in your MainTimeline or Main instance, depending on platform. You can add code there to pass that reference to other classes should you need it. The class should have a method (static, in your case) that'll accept a Stage parameter and store it somewhere inside the class.
public class UtilClass {
private static var theStage:Stage=null;
public static function initialize(s:Stage):void {
if (theStage) return; // we're initialized already
theStage=s;
}
// once you call this, you can "trace(theStage)" and get correct output
// other methods can also rely on theStage now.
}
Then you call UtilClass.initialize(stage); and you're set.
You will need to initialise your UtilClass and pass the stage reference. I recommend you to have a Class only for 'manage' Stage reference.
You could try something like this (just a quick example):
public class StageReference
{
public static const STAGE_DEFAULT:String = 'stageDefault';
protected static var _stageMap:Dictionary;
public static function getStage(id:String = StageReference.STAGE_DEFAULT):Stage
{
if (!(id in StageReference._getMap()))
throw new Error('Cannot get Stage ("' + id + '") before it has been set.');
return StageReference._getMap()[id];
}
public static function setStage(stage:Stage, id:String = StageReference.STAGE_DEFAULT):void
{
StageReference._getMap()[id] = stage;
}
public static function removeStage(id:String = StageReference.STAGE_DEFAULT):Boolean
{
if (!(id in StageReference._getMap()))
return false;
StageReference.setStage(null, id);
return true;
}
protected static function _getMap():Dictionary
{
if (!StageReference._stageMap) StageReference._stageMap = new Dictionary();
return StageReference._stageMap;
}
}
When you start your application (Main Class or where you start to include your logic)
StageReference.setStage(stage);
And when you need to get the stage reference
trace('Checking the Stage: ', StageReference.getStage());

Access caller object when using composition in AS3

In ActionScript3, I am trying to access the properties of the caller object from a composite.
public class Robot {
...
private var controlPanel:ControlPanel;
...
public function Robot() {
...
cPanel = new ControlPanel();
...
}
}
My ControlPanel needs to access properties from Robot instance, but I don't think I can pass this when calling the ControlPanel...
public class ControlPanel{
...
public function ControlPanel() {
//How can I refer back to robot properties ?
//
}
}
I believe I am in the case of composition as a Robot has a ControlPanel. I am thinking of using events, but there are many properties I need to access.
What would be the best way to solve this?
You can always just let ControlPanel store a reference to its own Robot object, like so:
// ControlPanel
private var robot:Robot;
public function ControlPanel(robot:Robot) {
this.robot = robot;
}
And then, when creating the control panel:
// Robot
public function Robot() {
controlPanel = new ControlPanel(this);
}
Alternatively, you could create an even system of sorts, and then let the control panel dispatch them. You could create your own ControlPanelEvent class, and then let the Robot itself handle the results. For example, let's say you change a property called foo in the control panel. You could dispatch it like this:
var event:ControlPanelEvent = new ControlPanelEvent(ControlPanelEvent.PROPERTY_CHANGE, "foo", value);
Then you'd receive it like this:
public function Robot() {
controlPanel = new ControlPanel();
controlPanel.addEventListener(ControlPanelEvent.PROPERTY_CHANGE, updateProperty);
}
public function updateProperty(event:ControlPanelEvent):void {
if (event.key == "foo") {
this.foo = event.value;
}
}
However, that's wordy and unnecessary. You could also use ActionScript's array access notation in the event handler, which would be a simple one-liner:
this[event.key] = event.value;
Still, that's not entirely secure, since you might not want the control panel to be able to update all of a robot's properties. Instead, you could maintain a simple map of configurable properties that the robot can have, and update that instead:
private var configuration:Dictionary = new Dictionary();
public function Robot() {
// ...
configuration.foo = "bar";
configuration.baz = "qux";
//...
}
public function updateProperty(event:ControlPanelEvent):void {
if (configuration.hasOwnProperty(event.key))
configuration[event.key] = event.value;
}
There you go. Of course, you could always just store the configuration map in the ControlPanel itself, and let the Robot pull from that, but if you absolutely need it as a property of the robot, here are a few solutions.
You should be able to pass 'this':
cPanel=new ControlPanel(this);
public class ControlPanel{
...
protected var _robot:Robot;
public function ControlPanel(robot:Robot){
_robot = robot;
}
}
You can't use arguments when extending display classes, but ControlPanel extends Object (by default as no extend is defined.
For display classes you can set the property after creating it:
cPanel=new ControlPanel();
cPanel.robot = this;
public class ControlPanel{
...
public var robot:Robot;
public function ControlPanel(){
}
}

How to Override Constants in ActionScript 3

I have the two following classes:
public class Parent{
static internal const _name:String = "Parent";
public function get name():String{
return _name;
}
}
public class Child{
static internal const _name:String = "Child";
}
If I create an instance of class Child and call its name() getter, since it will call the name() method it inherits from Parent, it returns "Parent". I could, of course, override the name() method:
public class Child{
static internal const _name:String = "Child";
override public function get name():String{
return _name;
}
}
That returns "Child". However, it seems silly to have to copy the exact same code of the method from the parent. Is there any simpler way to do this?
I would take a different approach by making the "name" property a requirement for the parent's constructor:
public class Parent
{
static internal var _name : String;
public function Parent(name : String = "Parent") {
_name = name;
}
public function get name() : String {
return _name;
}
}
Child Class:
public class Child extends Parent
{
public function Child() {
super("Child");
}
}
Firstly, you cannot override static methods or properties - they are not inherited, so no override for them.
Secondly, if you declared a constant to be of a complex type, it is not really a constant. I.e. if it is an object, then you can change its keys / values, if it is an array, you can add / remove members and so on.
But the desire to make this functionality more generic is understandable. So, what I'd do:
Have some property outside both parent and child, let say in class X, or package Y. Let it be package Y. So, you'd create a dictionary in package Y, let it be Y.names and in your name getter you'd do:
import Y.names;
. . .
public function get name() {
return names[(this as Object).constructor];
}
your names variable would be:
package Y {
public var names:Dictionary = generateNames();
internal function generateNames():Dictionary {
var result:Dictionary = new Dictionary();
result[ChildClass] = "child";
result[ParentClass] = "parent";
. . .
return result;
}
}
This way it would be sufficient to only implement name getter in super-class, and all inheriting classes will be able to use super-class code as is, no need to change anything. However, this means that some (maybe important) information pertaining to this class will be stored elsewhere (may be difficult to find, this is not the common way people program in AS3).
your implementation of get name should look like this, then the getter is one and each of the new classes needs to have it's own public static var _name defined:
//in the base class
public function get name():String
{
var _sName:String;
if ((this as Object).constructor._name)
{
_sName = (this as Object).constructor._name;
}
else
{
try
{
var o:Object = getSuperClass(this);
while (o)
{
if (o._name)
{
_sName = o._name;
break;
}
o = getSuperClass(o);
}
}
catch (e:*)
{}
}
return _sName;
}
//as found here: http://www.actionscriptdeveloper.co.uk/getting-the-class-of-an-object-in-as3/
public static function getSuperClass(o: Object): Object
{
var n: String = getQualifiedSuperclassName(o);
if (n == null)
return(null);
return getDefinitionByName(n);
}
the static members can be accessed only via class reference which we can get from constructor object, "this" will point to the current class in the inheritance chain so you can call this in parent class and it will point to a Child in a Child class.
[EDIT]
I've modified it so it tests for existance of the public static property _name if not found on "this" instance then in a loop the parent class is checked until one is found - like inheritance:)
I'm using this feature to create clone method: constructor as helper in clone method implementation
best regards
Why don't you store such a constant within a corresponding function instead of declaring an inaccessible constant?
class Parent {
...
public function get name():String { return 'Parent'; }
}
class Child extends Parent {
...
override public function get name():String { return 'Child'; }
}
By the way, if your Parent class is a descendant of DisplayObject, you should be careful with name property, as it's needed sometimes by operating code, e.g. getChildByName().
I have found something that seems to work. Any feedback is greatly appreciated:
public class Parent{
prototype._name = "Parent";
public function get name():String{
return this["_name"];
}
}
public class Child{
prototype._name = "Child";
}

AS3 - Error #1180: Call to a possibly undefined method kill.

This one is driving me crazy for a couple hours. I try to call a method kill(); (in function takeDamage()) which is in the same class, yet it won't find it.
package classes.ship
{
imports ...
public class Ship extends MovieClip
{
var speed:Number;
var shootLimiter:Number;
public static var health:Number;
public static var maxHealth:Number;
public function initialize()
{
var stageReff:Stage = this.stage as Stage;
stage.addEventListener(KeyboardEvent.KEY_DOWN, reportKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, reportKeyUp);
stage.addEventListener("enterFrame", move);
}
//code
public static function takeDamage(d):void
{
health -= d;
if(health <= 0)
{
health = 0;
kill();
}
Main.healthMeter.bar.scaleX = health/maxHealth;
}
public function kill():void
{
var boom = new Explosion();
stage.addChild(boom);
boom.x = this.x;
boom.y = this.y;
this.visible = false;
//Main.gameOver();
}
//code
}
}
Has it to do with var stageReff:Stage = this.stage as Stage; ?
Thanks in advance.
kill() is an instance method, but takeDamage is a static class method. You can't call instance methods from a static class method. You can only call instance methods when you have an instance reference to call it on.
nice simple one for early in the year!
You have declared the function 'takeDamage' as a static method - this means that it does not belong to a particular instance of the class Ship, instead it belongs to the Class itself. Static methods and properties can be a bit confusing if you are new to OOP, but are easily explained through a quick example:
Class Member Property
In this example we declare a new Class definition for a Ship where we can define the speed of the ship instance via setSpeed().
public class Ship {
private var speed : Number;
public function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Now we will create a couple of ships and set their speed:
var scoutShip : Ship = new Ship();
scoutShip.setSpeed(500); // Scout's are fast!
var cargoShip : Ship = new Ship();
cargoShip.setSpeed(10); // Cargo ships are sloooow.
trace("Scout Ship Speed: " + scoutShip.getSpeed()); // 500
trace("Cargo Ship Speed: " + cargoShip.getSpeed()); // 10
As you can see from the above, each new instance of Ship that we create can have its own Speed - this is a fundamental of Object Orientated Programming (where the Ship is the Object and it's speed is the data).
Static Property
Now we will create another class, this time called StaticShip which uses a static property instead, note the use of the static keyword:
public class StaticShip {
private static var speed : Number;
public function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Because the speed property is static it is shared across all instances of StaticShip; for example:
var scoutShip : StaticShip = new StaticShip();
scoutShip.setSpeed(500); // So the scout should move at 500
var cargoShip : StaticShip = new StaticShip();
cargoShip.setSpeed(10); // ... and the Cargo move at 10, as before
trace("Scout Ship Speed: " + scoutShip.getSpeed()); // 10
trace("Cargo Ship Speed: " + cargoShip.getSpeed()); // 10
Notice how both StaticShips move at 10 - this is because we set the Speed of the 'cargoShip' instance last - as the 'speed' property in StaticShip is declared static it is shared across all instances of that Class.
Now, just as you can have static properties in Classes, you can also have static functions. Usually, when you call a Class' method (ie: setSpeed()) you need to invoke that method on an instance (ie: scoutShip.setSpeed(500);), however, Static Methods allow you to interact with other static members of a given class, here's another example:
Static Method Example
public class StaticMethodShip {
private static var speed : Number;
// Note that setSpeed is now declared as static
public static function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Now, we can still create new instances of StaticMethodShip as before, but because we have now declared 'setSpeed' as static, we can't invoke setSpeed on an instance:
var scoutShip : StaticMethodShip = new StaticMethodShip();
// This call will trigger Error #1180 - Call to a possibly undefined Method because
// setSpeed was declared as static.
scoutShip.setSpeed(500);
Instead, we can now only invoke the setSpeed() method on the StaticMethodShip Class, ie:
// Set the speed of all StaticMethodShip instances.
StaticMethodShip.setSpeed(250); // all StaticMethodShips travel at 250.
// Proof!
var shipOne : StaticMethodShip = new StaticMethodShip();
var shipTwo : StaticMethodShip = new StaticMethodShip();
trace("ShipOne Speed: " + shipOne.getSpeed()); // 250
trace("ShipTwo Speed: " + shipTwo.getSpeed()); // 250
Static methods are useful when you want to define behaviour for all instances of a given Class (ie: all StaticMethodShips move at the specified speed, all fade out Tweens last for 0.25 seconds, etc); but they are also used in common design Patterns such as the Static Factory Method
Now, to the reason you are seeing your error - member level methods are able to invoke static methods, ie:
public class StaticExampleOne {
public static function getName() : String {
return "Robbe";
}
public function traceName() : void {
// traces 'Robbe'.
trace(getName());
}
}
In usage (new StaticExampleOne().traceName()) this works just fine - member methods can access static methods without problem, however this doesn't work the other way around:
public class StaticExampleTwo {
private var name : String = "Robbe";
public function getName() : void {
return this.name;
}
public static function traceName() : void {
// Throws Error #1180.
trace(getName());
}
}
This is because static methods have no scope (ie: They do not know which instance of the Class they are referring too because they can only reference other static members) and therefore can not access class level members (methods and properties).
To solve your problem you could introduce a new static property to Ship called 'STAGE' (typically static properties are written in ALL CAPS to differentiate them from member properties) and then make your kill() method static.
Hope this helps and good luck!
Jonny.