New property API in Cocos2d-html5 v3.0

New property API in Cocos2d-html5 v3.0

中文文档请移步

  1. The new style

Let’s directly take an example to show you what will be available in Cocos2d-html5 v3.0:

Old API New API
node.setPosition(x, y); node.x = x; node.y = y;
node.setRotation®; node.rotation = r;

So as you can see in the table, functions invocation are replaced with properties modification. In version 3.0, not only x, y and rotation, almost all properties of your node can be accessed like this. The properties list can be found in the end of this documentation.

Thanks to Javascript getter and setter, we can define getter function and setter function to a property. That’s how we defined our old functions for getter/setter of new properties. For example, node.x = x; actually invoked setPositionX function with the new x value, so don’t be afraid of the simplified APIs, it’s equivalent to the old function calls.

To define your own getter setter function for a property of an object, you can just use this line of code:

cc.defineGetterSetter(object, "propertyName", getterFunc, setterFunc);

Then each time you do var a = object.propertyName;, this retrieve the value of propertyName via getterFunc, and each time you want to modify the value: object.propertyName = newvalue; this pass the new value to setterFunc and try to modify its value.

As for the name of the properties, we proposed names close to CSS style which is very familiar to javascript developers.

  1. attr function of cc.Node

Individually, the property API is just a replacement of functions which permit to have more compact code, it’s not so exiting. But along with the properties access API, we also provided a even more useful function to cc.Node: attr function. Quite similar to jQuery’s attr function, it helps you to config all the properties you want together with just one function call.

node.attr({
	x: 20,
	y: 20,
	anchorX: 0.5,
	anchorY: 0.5,
	width: 400,
	height: 300,
	scale: 2
});

It support not only all properties available in the list of the end, but also your custom properties.

  1. Why and what changed

Why we want to do such a enormous change to our stable API? I think the obvious answer is already in the previous examples: The new API is far easier to code than the old API.

But what we really want to change, is not just the simplicity. Cocos2d-html5 has been complained for a long time by web developers about how difficult it is to learn and use. After compared with other html5 game engines, we found our engine is not designed for javascript developers. And indeed, the API of Cocos2d-html5 has always been the same with Cocos2d-x which serves C++ developers, and the original Cocos2d-iPhone also leaves its objective-C style API everywhere in the engine. Obviously, those APIs, which have been ported to Cocos2d-html5, are sometimes very strange for javascript developers.

So the main task of version 3.0 is to propose a fully refactored javascript style API to our user, and we are willing to take such a huge risk to change everything and ‘reboot’ Cocos2d-html5.

Back to properties, cc.Node and all its descendant classes are refactored with properties instead of getXXX() and setXXX(value) functions. There are also some property style API provided in a few other classes. All properties and related classes will be listed at the end of this document.

  1. About closure compiler

As attr uses key-value pairs to config nodes, there could be problems when we try to use the advanced mode of closure compiler to compile our project.

The problem is that keys won’t be compressed in advanced mode while our properties’ names will be compressed, this produce a mismatch issue between the attr function and the real properties. Fortunately, we have guaranteed the functionality of basic properties, which will be noted also in the list. For other properties or custom properties, you can add closure compiler expose annotation to avoid the problem. Note that this problem occurs only when developer try to use attr function to config properties.

/** @expose */
node.shaderProgram;

/** @expose */
node.customProperty;

node.attr({
	shaderProgram: program,
	customProperty: 0
});
  1. Extend getter/setter functions of the property

Another problem is that how can you inherit a class, and override the getter/setter function of the property. Good news for you, we have implement a built in solution to make this happen automatically. Here is an example when you want to override the x getter/setter in your custom Sprite sub class.

var MySprite = cc.Sprite.extend({
	ctor: function() {
		this._super();
		this.init();
	},
	getPositionX: function() {
		// Your own implementation
	},
	setPositionX: function(x) {
		// Your own implementation
	}
});

var mySprite = new MySprite();

Then mySprite.x = x; will invoke your custom setPositionX function, same for getter. What you have to make sure is the inherited getter/setter functions’ names must be the same as the parent class.

  1. List of properties

cc.Node

Property Type Accessibility Getter/Setter function Advanced Compress Ready
x Number R&W getPositionX, setPositionX yes
y Number R&W getPositionY, setPositionY yes
width Number R&W _getWidth, _setWidth yes
height Number R&W _getHeight, _setHeight yes
anchorX Number R&W _getAnchorX, _setAnchorX yes
anchorY Number R&W _getAnchorY, _setAnchorY yes
ignoreAnchor Boolean R&W isIgnoreAnchorPointForPosition, ignoreAnchorPointForPosition yes
skewX Number R&W getSkewX, setSkewX yes
skewY Number R&W getSkewY, setSkewY yes
rotation Number R&W getRotation, setRotation yes
rotationX Number R&W getRotationX, setRotationX yes
rotationY Number R&W getRotationY, setRotationY yes
scale Number R&W getScale, setScale yes
scaleX Number R&W getScaleX, setScaleX yes
scaleY Number R&W getScaleY, setScaleY yes
zIndex Number R&W getZOrder, setZOrder yes
vertexZ Number R&W getVertexZ, setVertexZ yes
children Array Readonly getChildren no
childrenCount Number Readonly getChildrenCount no
parent cc.Node R&W getParent, setParent yes
visible Boolean R&W isVisible, setVisible yes
running Boolean Readonly isRunning no
tag Number R&W getTag, setTag yes
userData Object R&W getUserData, setUserData yes
userObject Object R&W getUserObject, setUserObject yes
arrivalOrder Number R&W getArrivalOrder, setArrivalOrder yes
actionManager cc.ActionManager R&W getActionManager, setActionManager yes
scheduler cc.Scheduler R&W getScheduler, setScheduler yes
grid cc.GridBase R&W getGrid, setGrid no
shaderProgram cc.GLProgram R&W getShaderProgram, setShaderProgram no
glServerState Number R&W getGLServerState, setGLServerState no

cc.NodeRGBA

Extend from cc.Node

Property Type Accessibility Old API Advanced Compress Ready
opacity Number R&W getOpacity, setOpacity yes
opacityModifyRGB Boolean R&W isOpacityModifyRGB, setOpacityModifyRGB yes
cascadeOpacity Boolean R&W isCascadeOpacity, setCascadeOpacity yes
color cc.Color R&W getColor, setColor yes
cascadeColor Boolean R&W isCascadeColor, setCascadeColor yes

cc.Sprite

Extend from cc.NodeRGBA

Property Type Accessibility Old API Advanced Compress Ready
dirty Boolean R&W isDirty, setDirty yes
flippedX Boolean R&W isFlippedX, setFlippedX yes
flippedY Boolean R&W isFlippedY, setFlippedY yes
offsetX Number Readonly _getOffsetX no
offsetY Number Readonly _getOffsetY no
atlasIndex Number R&W getAtlasIndex, setAtlasIndex yes
texture cc.Texture2D R&W getTexture, setTexture yes
textureRectRotated Boolean Readonly isTextureRectRotated no
textureAtlas cc.TextureAtlas R&W getTextureAtlas, setTextureAtlas yes
batchNode cc.SpriteBatchNode R&W getSpriteBatchNode, setSpriteBatchNode yes
quad cc.V3F_C4B_T2F_Quad Readonly getQuad no

cc.LabelTTF

Extend from cc.Sprite

Property Type Accessibility Old API Advanced Compress Ready
string String R&W getString, setString yes
textAlign Number R&W getHorizontalAlignement, setHorizontalAlignement yes
verticalAlign Number R&W getVerticalAlignement, setVerticalAlignement yes
font String R&W _getFont, _setFont yes
fontSize Number R&W getFontSize, setFontSize yes
fontName String R&W getFontName, setFontName yes
boundingWidth Number R&W _getBoundingWidth, _setBoundingWidth yes
boundingHeight Number R&W _getBoundingHeight, _setBoundingHeight yes
fillStyle cc.Color R&W setFontFillColor yes
strokeStyle cc.Color R&W _getStrokeStyle, _setStrokeStyle yes
lineWidth Number R&W _getLineWidth, _setLineWidth yes
shadowOffsetX Number R&W _getShadowOffsetX, _setShadowOffsetX yes
shadowOffsetY Number R&W _getShadowOffsetY, _setShadowOffsetY yes
shadowOpacity Number R&W _getShadowOpacity, _setShadowOpacity yes
shadowBlur Number R&W _getShadowBlur, _setShadowBlur yes

cc.Texture2D

Property Type Accessibility Old API Advanced Compress Ready
name String Readonly getName no
pixelFormat Number Readonly getPixelFormat no
pixelsWidth Number Readonly getPixelsWide no
pixelsHeight Number Readonly getPixelsHigh no
width Number R&W _getWidth, _setWidth no
height Number R&W _getHeight, _setHeight no
shaderProgram cc.GLProgram R&W getShaderProgram, setShaderProgram no
maxS Number R&W getMaxS, setMaxS no
maxT Number R&W getMaxT, setMaxT no

// IN CONSTRUCTION

Hi, dear Cocos2d-html5 developers !

I put this document here to collect your feed backs about the new property API in version 3.0 which will be available in March.
There will be some great changes and we don’t know if you will like it, that’s the purpose of this post.

Please tell us if you like it or not, and any comment, suggestions or critics are the most appreciated.

Thank you all for helping Cocos2d-html5 get better.

Huabin

Hi pandamicro,

This new API will be JSB ready?. This new api sounds cool for fast developing. But, this approach will let aside the OO paradigm or will be backward compatible?

Cheers.

Hi @mmartis

What do you mean by “let aside the OO paradigm” ?
The new API will soon be JSB ready.
Backward compatibility is really a issue that we are struggling, we don’t want user to get confused by different ways of configuration, but we can also comprehend the need you are mentioning. However, a part of 3.0 won’t be backward compatible, it is for sure, for example, we are refactoring the bootstrapping process which won’t be backward compatible. The new event manager which will replace event dispatcher won’t be neither.

There are still the possibility to make getter/setter backward compatible. But we want to know what do you think if we remove all old get/set functions ?

Huabin

First of all: great! Big thanks and congratulations on this effort!

Secondly, are getPosition() and setPosition(cc.p()) (or setPosition(x, y)) gone completely too? Or will they remain?

@ZippoLag

That’s a good question, and that’s also what we want to learn from you.
As I said, we don’t want new users to get confused by different ways of configuration, so our intention is to remove them completely, but it is not done yet.
So How do you think if they are all gone?

Huabin

Well, maybe it’s just that I’m too used to the way the API is right now, but it seems to me that there are times where it’s useful to have the position. And remembering that currently getPosition() doesn’t return a copy of the position but rather a reference to it, then for example if I had coded something like var positionBackup = cc.p(myNode.getPosition()); it would either have to get turned into:
a. var positionBackup = cc.p(myNode.x, myNode.y);
b. var positionBackup = cc.p(myNode); //Since Node has properties "x" and "y", cc.p() should be able to make a copy like that?

I can’t really say which of all of them would be more comftible (or more compliant with some stablished standard, I don’t have that much of experience either). Maybe we should take a look at sample code (like from the games included in the samples folder) and see what changes would be easier to make or would feel more natural?

@ZippoLag

For position, it is possible to make a “pos” property, and it will return a copy of the position. In the current version, you can get position’s reference, but you can’t modify it, that’s pretty odd sometimes:

var pos = node1.getPosition();
pos.x = 0;
node2.setPosition(pos);

This will trigger a warning and the pos value won’t get changed, because the position reference is readonly. In the other hand, if we return every time a copy of the position, and developer doesn’t pay attention, like use getPosition in each update, it will create too much useless object.
That’s also why we temporarily disabled “pos” property. What’s your opinion about this problem?

Huabin

Well, rather than that pos property returning a copy, wouldn’t it make more sense to make getPosition() return a copy then? It could be stressed that for read-only the use of .x and .y is preferred for performance reasons in the docs.

I’m still not sure, I’m currently busy, but I’ll check the samples (and my own code) for common usage to see if I get some ideas as soon as I can. (Maybe we should make a poll? Maybe this thread -and the one about the new event handler- should be posted on facebook or homepage to get more attention?)

And for real experience of the refactoration, you can take a look at the code in tests_js_3.0 branch of our samples: https://github.com/cocos2d/cocos2d-js-tests/tree/tests_js_3.0

I have refactored games/MoonWarriors, games/FruitAttack and tests with new property style.

Then what about leave all old functions and in the same time propose the new property style ?

node.setPosition(x, y);
node.x = x;
node.y = y;

I’m worried about that developers will think function way is more secure than the property way, but in fact, they are the same.

And thanks a lot for your comments !

@pandamicro I mean, if we will be able to extend our classes using extends and using “_private” properties and defining its getter/setters. Or if the new ways of making the things will be defining the properties as public vars and access them directly as in the framework, and also using the attr function?

Cheers

@mmartis

The properties won’t be public vars and accessed directly, they will be accessed via functions, so if you extend a class with properties, you can simply extend their original get/set function to make the property be accessed via your extended functions.

pandamicro wrote:

Then what about leave all old functions and in the same time propose the new property style ?

Well, I guess that if the docs (and the release notes) explain that they are the same, there should be no problem. If they are the same, people could just use whatever they feel fits their code stlye better (althought, yeah, people do tend to assume wrongly and misplace their efforts in the search of efficiency).

mmartis wrote:

@pandamicro I mean, if we will be able to extend our classes using extends and using “_private” properties and defining its getter/setters. Or if the new ways of making the things will be defining the properties as public vars and access them directly as in the framework, and also using the attr function?

Cheers

More precisely, there isn’t such a thing as a private variable in javascript (ok, except if you use closures), so far the _ prefix is just a notation. We SHOULDN’T access those variables/properties from code outside the object, but that doesn’t mean we can’t.

pandamicro wrote:

@mmartis

The properties won’t be public vars and accessed directly, they will be accessed via functions, so if you extend a class with properties, you can simply extend their original get/set function to make the property be accessed via your extended functions.

I think we have a slight problem with something here: I’m getting a feeling that most people approaching this engine for the first time only have basic knowledge of JavaScript, and while they probably know some other OOP language, they are not familiar with properties getter/setter, or at least not in the way JS implements them. (at least, that was my case, I didn’t really know how to use them up to a few weeks ago actually). So maybe extra emphasis should be made in the docs about how properties work? (and how people can extend them in their own clases?)

ZippoLag wrote:

I think we have a slight problem with something here: I’m getting a feeling that most people approaching this engine for the first time only have basic knowledge of JavaScript, and while they probably know some other OOP language, they are not familiar with properties getter/setter, or at least not in the way JS implements them. (at least, that was my case, I didn’t really know how to use them up to a few weeks ago actually). So maybe extra emphasis should be made in the docs about how properties work? (and how people can extend them in their own clases?)

Indeed, that’s important, if developers understand the mechanism behind this, maybe they will feel much more comfortable to choose their own preferred code style. I will add this section later.

Huabin

Congrats on the new improvements!
But this will come as a blow to developers who were expecting API convergence between Cocos2d-X and Cocos2d-html5 codebases.

A better approach would be to make emscripten work for Cocos2d-X c++ codebase. Managing and migrating multiple codebases,will now obliterate the major advantage of the Cocos2D-X ecocsystem.

Also, please clarify the divergence between Cocos2d-x JSB and Cocos2d-html5 - affected by these changes in a documents on cocos-docs.

@indygamer: That’s a good point too: so far it’s sometimes difficult to find some examples and explanations for the JavaScript flavor of Cocos2D, but as long as you can find a c++ (or even sometimes an old objective-c) example, you can usualy copy-paste and manually “translate” that code into a JS equivalent. But we would lose this advantage with this changes, right?

@indygamer
@ZippoLag

Sure the changes will have some side effects, like you said, some differences between cocos2d-x and cocos2d-html5. Although, we also think for a long time that a strict consistent API makes our engine very hard to use, and the C++/Obj-C style API is sometime very unnatural in javascript code. That makes many developers keep away from it, that’s the original idea of these new APIs in v3.0.
About make these changes also in Cocos2d-x, these use javascript’s advantage which can’t be applied to C++ version and C++ developers have their own code style, so I don’t think it’s a good idea.

Back to details, first of all, JSB functionalities will be guarantied in the stable version of v3.0, so you will always be able to use the same code base between Cocos2d-html5 and JSB.

Secondly, these changes won’t change the gene of Cocos2d in Cocos2d-html5, the priority for v3.0 is to simplify the APIs, not to change the base. So ideas developers learn from Cocos2d-x or Cocos2d-iPhone examples can also be used in Cocos2d-html5, except that in version 3.0 the translation work will be a little bit more difficult.
To be more specific, the property API may be (not sure yet) backward compatible so that you can choose your own preferred style. The event manager is based on the event dispatcher of Cocos2d-x v3.0, simpler API with the same design. There will be also docs about new game bootstrapping process which will be much more easy and clear, many singleton classes will be refactored by a simple javascript object which makes them more efficient and easy to use, and so on.

Please keep an eye on our forum to discover more informations and give us any comments you like.
Thanks

Hi, everyone

The doc has been updated with two improvement:
How to define your own getter/setter
How to inherit the property with your custom getter/setter

Please take a look at it.

Huabin

@slawo

You don’t need to worry about that, JS Bindings will be upgraded to fit Cocos2d-html5 v3.0, you use always the same JS code base to have html5 version and native JSB version
But about the API style, what’s your opinion?

Huabin