I. Causes
on the client The most disgusting work in game development is UI-related, and while there is a visualization tool like Cocostudio, there are a lot of code-access controls in the interface that need to write too many repetitive code such as:
Load UI config file var root = Ccs.uiReader.widgetFromJsonFile ("Res/cocosui/uieditortest/uibutton_editor/uibutton_ Editor_1.json "); This._mainnode.addchild (root); Query the back control and add the event response var Back_label = ccui.helper.seekWidgetByName (Root, "back"); Back_label.addtoucheventlistener (this.backevent,this); Query the button_123 control and add the event response var button = Root.getchildbyname (Root, "button_123"); Button.addtoucheventlistener (this.touchevent,this);</span>
above is the most direct way to access the control. The problem is, if there are 10, 20, or more UI controls in a UI interface that need to be manipulated, do we have the UI, the logic developers, or do we have time to play happily? is there any way to access the UI component and receive UI event responses without having to write the code?
two. Thinking
for mobile games, especially for card-like games, the 70%~80% client workload is in UI layout and logic. the seekwidgetbyname,getchildbyname,addtoucheventlistener functions above will be flooded in the client code, Impostors the number of lines of code we have.
I have had the development experience of QT. QT also has its own UI design tool, which generates an XML UI configuration file. There are two ways to use this XML: The first way: Use Qt's own compilation tool to generate a C + + code file for XML translation, which is to create various controls based on the information in the XML, set coordinates \ properties \ events, and so on. The second way: in the program, the XML file is loaded into a node using the Uiloader tool class. And then call the QT function implementationAutomatic correlation of signals/slots. The principle of automatic binding of signals/slots (events) is the requirement to write an event handler, in the following format:
void On_ Control Name _ signal name (parameter);
specific how to use it is not detailed, interested friends can go to see for themselves. According to this function of QT, we can not automatically bind Coccostudio output UI file in Cocos2d-js.
three.name-Life conventions
1. Code Name Conventions
According to the COCOS2D-JS code style, we agreed:(1) Class member variable an underscore "_" followed by an English word in a camel-named format.For example: Private functions in the _loginbutton, _closebutton, _namelabel (2) classes are also used in the same way.For example: _onloginbuttontouchbegan:function () {...}
2. UI Naming conventions
In the Cocostudioui editor, we follow the naming conventions for member variables in the code above. Name the control that needs to be accessed by code beginning with "_" followed by the English word in camel-named format. Please see:
3. Ccui Control event naming
ccui. There are two types of widget event registrations:1). The regular touch events are: ccui. Widget.touch_began Touch Start (press) ccui. Widget.touch_moved Touch Move (move) ccui. widget.touch_ended Touch End (lift)
Ccui. Widget.touch_canceled Touch Cancel (generally useless)We use widgets. Addtoucheventlistener (selector, target) registers a touch event with the control and sets the callback function.
2). Control Special Events: For example, a checkbox: ccui. Checkbox.event_selected ccui. Checkbox.event_UNSELECTED Another example: TextField: Ccui. Textfield.event_attach_with_imeCcui. Textfield.event_detach_with_imeCcui. Textfield.event_insert_textCcui. Textfield.event_delete_backwardThis type of event requires the use of widgets. AddEventListener (selector, target) to register.
Here'sSelector is our callback function, we need to name and implement this function, the event type is identified by parameters:
Ctor:function () {this._super ();... button.addtoucheventlistener (this._onbuttonevent, this);},_onbuttonevent: function (sender, type) {switch (type) {case Ccui. Widget.touch_began: ...; Return True;case Ccui. Widget.touch_moved: ...; Break;case Ccui. widget.touch_ended: ...; Break;}}
This "_onbuttonevent" is the name we take for the event function, if we press: "
prefix + control name (Take drop dash)+ event name "Name the control event functionTo illustrate:the control name is: _ Button The event name is: _on button Touchbegan, _on button Touchmoved,_onButtontouchended
four. Code implementation
with the above conventions, we can begin to implement the binding of the UI. 1. Define a list of controls that are automatically bound, and we list the commonly used control types and event names.
Touch event Sz. Uiloader.touchevents = ["Touchbegan", "touchmoved", "touchended"];//control event list sz. uiloader.widgetevents = [ //button {widgettype:ccui. Button, Events:sz. Uiloader.touchevents}, //imageview {widgettype:ccui. ImageView, Events:sz. Uiloader.touchevents}, //textfiled {widgettype:ccui. TextField, events: ["Attachwithime", "Detachwithime", "InsertText", "Deletebackward"]}, //checkbox { Widgettype:ccui. CheckBox, events: ["Selected", "unselected"]}, //listview {widgettype:ccui. ListView, events:["SelectedItem"]}, //panel {widgettype:ccui. Layout, Events:sz. Uiloader.touchevents}, //bmfont {widgettype:ccui. Textbmfont, Events:sz. Uiloader.touchevents}, //last must null NULL];
this sz. The uiloader.widgetevents array can add itself to the component that needs to be bound.
2. Logic flow 1). Use loader to load the UI file and pass in target as the current layer. all event and control variables are bound to the target. 2) traverse the loaded child node (childnode) to check if the prefix is open with "_" . and whether the node type is in the widgetevents array.
3) . Bind the Childnode to the target.
4) Extract the childnode event function name and check if Target has any of these functions present.
5). Register an event response for Widgetnode. 6). The load class receives the event response and forwards the event to the corresponding target on the event handler function.
concrete implementation of 3.UI load class
Sz. UILoader = cc. Class.extend ({_eventprefix:null, _memberprefix:null,/** * Loading UI files * @param target binds jsonfile loaded nodes to the Target * @param the JSON file generated by the Jsonfile Cocostudio UI Editor */widgetfromjsonfile:function (target, jsonfile, options) { Cc.assert (target && jsonfile); if (!options) {options = {}; } this._eventprefix = Options.eventprefix | | Sz. Uiloader.default_event_prefix; This._memberprefix = Options.memberprefix | | Sz. Uiloader.default_member_prefix; var rootNode = Ccs.uiReader.widgetFromJsonFile (jsonfile); if (!rootnode) {cc.log ("Load JSON file failed"); } Target.rootnode = RootNode; Target.addchild (RootNode); This._bindmenbers (RootNode, target); },/** * Recursive member binding to Rootwidget sub-node * @param rootwidget * @param target * @private */_bindmenbers : function (Rootwidget, target) {var widgetname, children = RootwidGet.getchildren (); var = this; Children.foreach (function (widget) {widgetname = Widget.getname (); The control name exists, bound to the target on var prefix = widgetname.substr (0, self._memberprefix.length); if (prefix = = = Self._memberprefix) {Target[widgetname] = widget; Self._registerwidgetevent (target, widget); }//Bound child controls, you can implement: A._b._c._d Access child controls if (!rootwidget[widgetname]) {Rootwidget[widgetname ] = widget; }//If there are child nodes, recursively go in if (Widget.getchildrencount ()) {self._bindmenbers (widget, target); } }); },/** * Get control event * @param widget * @returns {*} */_getwidgetevent:function (widget) {var bin Dwidgetevent = null; var events = Sz. uiloader.widgetevents; for (var i = 0; i < events.length; i++) {bindwidgetevent = events[i]; if (widget instanceofBindwidgetevent.widgettype) {break; }} return bindwidgetevent; },/** * Register control event * @param target * @param widget * @private */_registerwidgetevent:function (tar Get, widget) {var name = Widget.getname (); Intercept prefix, capital letter var newName = name[this._memberprefix.length].touppercase () + name.slice (this._memberprefix.length + 1 ); var eventName = this._eventprefix + newName + "Event"; var isbindevent = false; if (Target[eventname]) {isbindevent = true; } else {//take things widget name var widgetevent = this._getwidgetevent (widget); if (!widgetevent) {return; }//Check things function, generate event an array group var eventnamearray = []; for (var i = 0; i < widgetEvent.events.length; i++) {eventName = This._eventprefix + newName + Widgetev Ent.events[i]; Eventnamearray.push (EventName); if (Cc.isfunction (Target[eventname])) {isbindevent = true; }}}//event response function var = this; var eventfunc = function (sender, type) {var callBack; if (Eventnamearray) {var funcName = Eventnamearray[type]; CallBack = Target[funcname]; } else {callBack = Target[eventname]; } if (self._onwidgetevent) {self._onwidgetevent (sender, type); } if (CallBack) {return callback.call (target, sender, type); } }; Register Event Listener if (isbindevent) {widget.settouchenabled (true); if (Widget.addeventlistener) {Widget.addeventlistener (eventfunc, target); } else {Widget.addtoucheventlistener (eventfunc, target); }}}); sz.uiloader = new Sz. UILoader ();
Everything is ready, so let's see how we can use it in specific code:
Gamelayer = cc. Layer.extend ({ctor:function () {this._super ();//loading UI files, binding controls and events to Thissz.uiloader.widgetFromJsonFile (this, "res/ Demologin.exportjson ");//immediate access to the control's property method Cc.log (This._closebutton.getname ()); _closebutton event handler for},/* * Touchbegan * /_onclosebuttontouchbegan:function (sender) {cc.log ("_onclosebuttontouchbegan");});
Now look at my client code is not much more concise than before! Complete code can be downloaded to Githut: Https://github.com/ShawnZhang2015/UILoader
Implement automatic binding of Cocostudioui controls and events in Cocos2d-js