require("luaScript.Extension.CCExt") require("luaScript.Extension.MathExt") require("luaScript.cc.debug") require("luaScript.Tools.Nodes.Transform") cc.Node.ClassName = "Node"; function cc.Node:cloneLua(node) end function cc.Node:loadFromXmlNode(xmlNode) cc.Transform.loadFromXmlNode(self , xmlNode); self:setName(xmlNode.Name); self:setLocalZOrder(xmlNode.LocalZOrder) if xmlNode.RenderOffset ~= nil then self:setRenderOffset(xmlNode.RenderOffset) end end function cc.Node:createNode() local node = cc.Node:create(); return node; end function cc.StreamObject:saveToBinaryString() return string.toLuaString(self:saveToStream()); end function cc.StreamObject:createFromBinaryString(str) local func , err = loadstring("return " .. str); if func == nil then error(err); end local data = func(); return cc.StreamObject:loadFromStream(data); end -- 获得选择用的世界包围盒,用来编辑器框选的 function cc.Node:getSelectBox() return self:getSelfBoundingBox(); end -- 计算矩形rect是否跟节点相交,用来给编辑器框选的 -- rect 的坐标系是0-1 function cc.Node:selectTest(rect) local frustum = cc.Frustum:new(app.mainCamera:pickRectVPMatrix(rect)); return frustum:intersectsBoundingBox(self:getSelectBox()); end -- 遍历所有子节点 function cc.Node:visitNode(func) if func(self) == false then return false; end local children = self:getChildren(); if children then for i , v in ipairs(children) do local child = v; if cc.Node.visitNode(child , func) == false then return false; end end end return true; end -- 获得根节点 function cc.Node:getRootNode() local parent = self:getParent(); if parent then return parent:getRootNode(); else return self; end end -- 获得这个节点的世界位置 function cc.Node:getWorldPosition() local parent = self:getParent(); if parent then return parent:convertToWorldSpace(self:getTranslation()); else return self:getTranslation(); end end -- 设置这个节点的世界位置 function cc.Node:setWorldPosition(pos) local parent = self:getParent(); if parent then self:setTranslation(parent:convertToNodeSpace(pos)); else self:setTranslation(pos); end end -- 获得这个节点的世界位置 function cc.Node:getWorldPositionX() return self:getWorldPosition().x; end -- 获得这个节点的世界位置 function cc.Node:getWorldPositionY() return self:getWorldPosition().y; end -- 设置这个节点的世界位置 function cc.Node:setWorldPositionX(x) local pos = self:getWorldPosition(); pos.x = x; self:setWorldPosition(pos); end -- 设置这个节点的世界位置 function cc.Node:setWorldPositionY(y) local pos = self:getWorldPosition(); pos.y = y; self:setWorldPosition(pos); end -- 运行静态时间的actions function cc.Node:runActions(...) local action = createActionArray(...); self:runAction(action); return action; end -- 每帧运行一次 function cc.Node:runEveryFrame(func) local action = cc.RepeatForever:create(cc.Sequence:create(cc.CallFunc:create(func))); self:runAction(action); return action; end -- 下一帧运行一次 function cc.Node:runInNextFrame(func) local action = cc.Sequence:create(cc.CallFunc:create(func)); self:runAction(action); return action; end -- 延迟几秒后执行 function cc.Node:runDelay(delay , func) return self:runActions(cc.DelayTime:create(delay) , func); end -- 运行动态时间的actions function cc.Node:runDynamicTimeActions(...) local action = createDynamicTimeActionArray(...); self:runAction(action); return action; end function cc.Node:runSpawnActions(...) local action = createSpawnActions(...); self:runAction(action); return action; end -- 注册点击事件(不管节点大小,全屏的,但是会根据渲染顺序派发),所有参数都可为空 function cc.Node:registerTouch(onTouchBegan , onTouchMoved , onTouchEnded , onTouchCancelled) -- 侦听鼠标触摸事件 local touchListener = cc.EventListenerTouchOneByOne:create() touchListener:setSwallowTouches(true); local eventDispatcher = self:getEventDispatcher() if onTouchBegan then touchListener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN) end if onTouchMoved then touchListener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED) end if onTouchEnded then touchListener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED) end if onTouchCancelled then touchListener:registerScriptHandler(onTouchCancelled, cc.Handler.EVENT_TOUCH_CANCELLED) end eventDispatcher:addEventListenerWithSceneGraphPriority(touchListener, self) return touchListener; end -- 注册按下时的点击事件(判断节点包围盒是否与点击点相交,全屏的,会根据渲染顺序派发) -- @onClick 点击回调:onClick(clickPoint) -- boundingbox 传进来一个本地包围盒(内部会通过node的世界矩阵转换成世界包围盒),如不传则使用node的世界包围盒 function cc.Node:registerClick(onClick , boundingbox) local function onTouchBegan(touch , event) if not self:isVisibleR() then return false; end -- 获取点击的射线 local ray = self:convertTouchToCameraRay(touch); local distance; if boundingbox then local transformed = cc.BoundingBox:new(boundingbox:getMin() , boundingbox:getMax()); transformed:transform(self:getWorldMatrix()); distance = ray:intersectsBoundingBox(transformed); else distance = ray:intersectsBoundingBox(self:getBoundingBox()); end if distance >= 0 then local clickPoint = ray:getPoint(distance); if onClick(clickPoint) == false then return false; end return true; else return false; end return false; end self:setTouchEnabled(true); self:registerTouch(onTouchBegan); end -- 注册弹起时的点击事件(判断节点包围盒是否与点击点相交,全屏的,会根据渲染顺序派发) -- @onClick 点击回调:onClick(clickPoint) -- boundingbox 传进来一个本地包围盒(内部会通过node的世界矩阵转换成世界包围盒),如不传则使用node的世界包围盒 function cc.Node:registerMouseUp(onClick , boundingbox) local function onTouchBegan(touch , event) if not self:isVisibleR() then return false; end -- 获取点击的射线 local ray = self:convertTouchToCameraRay(touch); local distance; if boundingbox then local transformed = cc.BoundingBox:new(boundingbox:getMin() , boundingbox:getMax()); transformed:transform(self:getWorldMatrix()); distance = ray:intersectsBoundingBox(transformed); else distance = ray:intersectsBoundingBox(self:getBoundingBox()); end if distance >= 0 then return true; else return false; end return false; end local function onTouchEnded(touch , event) if not self:isVisibleR() then return false; end -- 获取点击的射线 local ray = self:convertTouchToCameraRay(touch); local distance; if boundingbox then local transformed = cc.BoundingBox:new(boundingbox:getMin() , boundingbox:getMax()); transformed:transform(self:getWorldMatrix()); distance = ray:intersectsBoundingBox(transformed); else distance = ray:intersectsBoundingBox(self:getBoundingBox()); end if distance >= 0 then local clickPoint = ray:getPoint(distance); if onClick(clickPoint) == false then return false; end return true; else return false; end return false; end self:registerTouch(onTouchBegan , nil , onTouchEnded); end -- 显示包围盒 -- boundingbox 传进来一个本地包围盒(内部会通过node的世界矩阵转换成世界包围盒),如不传则使用node的世界包围盒 function cc.Node:showBoundingBox(boundingbox) local glNode = gl.glNodeCreate() glNode:setAnchorPoint(cc.p(0.5, 0.5)) local material3d = cc.MaterialCache:getInstance():load("preload/shaders/ccDefault.material#ShaderPosition_uColor3D"); cc.Default2DMaterials:getInstance():bindValue(material3d:getParameter("CC_MVPMatrix") , "WORLD_VIEW_PROJECTION_MATRIX"); local function primitivesDraw(transform, transformUpdated) if not tolua.isnull(self) then cc.DrawPrimitives.setMaterial(material3d); -- 绑定相机、世界矩阵 cc.DrawPrimitives.setCamera(self:getActiveCamera()); cc.DrawPrimitives.setWorldTransform(cc.Mat4:identity()); -- 画矩形 gl.lineWidth( 1 ) cc.DrawPrimitives.drawColor4B(0, 255, 0, 255) if boundingbox then local transformed = cc.BoundingBox:new(boundingbox:getMin() , boundingbox:getMax()); transformed:transform(self:getWorldMatrix()); cc.DrawPrimitives.drawBoundingBox(transformed) else cc.DrawPrimitives.drawBoundingBox(self:getBoundingBox()) end -- 状态恢复 gl.lineWidth(1) cc.DrawPrimitives.drawColor4B(255,255,255,255) cc.DrawPrimitives.setPointSize(1) -- 材质状态恢复 cc.DrawPrimitives.setCamera(nil); cc.DrawPrimitives.setMaterial(nil); end end glNode:registerScriptDrawHandler(primitivesDraw) self:addChild(glNode); return glNode end -- 使用这个节点当作源模型和源点来播放一个ce function cc.Node:playCE(ceFile , onPlayEnd) -- 创建一个源模型、源点、目标模型、目标点 local params = createDefaultCombineEffectParams(); params.ParentNode = self:getParent(); table.insert(params.SourceNode, self); table.insert(params.SourcePos, self:getTranslation()); local ce = createCombineEffect(ceFile); local action = nil if ce then action = cc.CombineEffectAction:createWithInstance(ce, params, nil, function()if onPlayEnd then onPlayEnd()end; end) self:runAction(action) end return action end -- 兼容老接口 function cc.Node:registerScriptHandler(listener) local function callback(node , eventType) if eventType == cc.NodeEvent.OnEnter then listener("enter"); elseif eventType == cc.NodeEvent.OnExit then listener("exit"); elseif eventType == cc.NodeEvent.OnEnterTransitionDidFinish then listener("enterTransitionFinish"); elseif eventType == cc.NodeEvent.OnExitTransitionDidStart then listener("exitTransitionStart"); elseif eventType == cc.NodeEvent.OnCleanup then listener("cleanup"); elseif eventType == cc.NodeEvent.OnDestruct then listener("destruct"); end end return self:addNodeEventListener(callback); end function cc.Node:unregisterScriptHandler(eventId) if eventId then self:removeNodeEventListener(eventId); else self:removeAllNodeEventListener(); end end -- 禁用这个Widget下的所有点击 function cc.Node:disableAllTouch() local function visit(node) if node.setTouchEnabled then if node:isTouchEnabled() then node.OldTouchEnabled = node:isTouchEnabled(); node:setTouchEnabled(false); end end end self:visitNode(visit); end -- 恢复这个Widget下的所有点击 function cc.Node:restoreAllTouch() local function visit(node) if node.setTouchEnabled then if node.OldTouchEnabled == true then node:setTouchEnabled(true); node.OldTouchEnabled = nil; end end end self:visitNode(visit); end -- 设置一个剩余时间,并且每秒倒数,callback(ui , value) function cc.Node:startRemainTime(seconds , callback) -- 打印一下,是哪个地方在调用这个接口 logD("cc.Node:startRemainTime()", debug.traceback()) seconds = tonumber(seconds) if not seconds or seconds <= 0 then return end -- 设置倒计时 local remainTimePacket = RemainTimePacket:new(); remainTimePacket.remainTime:setRemainTime(math.floor(seconds)) self:bind(remainTimePacket.remainTime, "Value", callback) end -- 把节点基本信息dump到一个表里返回(调试用) function dumpNode(node) local dumped = {}; dumped.Name = node:getName(); dumped.ClassName = tolua.type(node); local children = {}; for i , v in ipairs(node:getChildren()) do table.insert(children , dumpNode(v)); end dumped.Children = children; return dumped; end -- 把节点基本信息dump到一个文件(调试用) function dumpNodeToFile(node , filename) local dumped = dumpNode(node); table.saveFile(dumped , filename); end