cocos2d-Lua的运行流程与场景

打开工程根目录下的配置文件config.json:
{
"init_cfg": {
"isLandscape": true,
"isWindowTop": false,
"name": "redDefense",
"width": 1920,
"height": 1080,
"entry": "src/main.lua",
"consolePort": 6050,
"uploadPort": 6060,
"debugPort": 10000,
"forwardConsolePort": 10089,
"forwardUploadPort": 10091
},
"simulator_screen_size": [
{
"title": "iPhone 3Gs (480x320)",
"width": 480,
"height": 320
},
{
"title": "iPhone 4 (960x640)",
"width": 960,
"height": 640
},
{
"title": "iPhone 5 (1136x640)",
"width": 1136,
"height": 640
},
{
"title": "iPad (1024x768)",
"width": 1024,
"height": 768
},
{
"title": "iPad Retina (2048x1536)",
"width": 2048,
"height": 1536
},
{
"title": "Android (800x480)",
"width": 800,
"height": 480
},
{
"title": "Android (854x480)",
"width": 854,
"height": 480
},
{
"title": "Android (1280x720)",
"width": 1280,
"height": 720
},
{
"title": "Android (1920x1080)",
"width": 1920,
"height": 1080
}
]
}
可以看到 "entry": "src/main.lua",也就是说入口文件是main.lua,进而打开main.lua:
cc.FileUtils:getInstance():setPopupNotify(false)
cc.FileUtils:getInstance():addSearchPath("src/")
cc.FileUtils:getInstance():addSearchPath("res/")

require "config"
require "cocos.init"

local function main()
require("app.MyApp"):create():run()
end

local status, msg = xpcall(main, __G__TRACKBACK__)
if not status then
print(msg)
end
执行main函数,main函数里加载MyApp创建并运行,进而打开MyApp.lua:
local MyApp = class("MyApp", cc.load("mvc").AppBase)

function MyApp:onCreate()
math.randomseed(os.time())
end

return MyApp
这里就有点看头,MyApp仅仅是继承自AppBase,onCreate函数只是初始化了下随机数种子,也就意味着更多的操作在AppBase中,我们打开分析:
local AppBase = class("AppBase")

function AppBase:ctor(configs)
self.configs_ = {
viewsRoot = "app.views",
modelsRoot = "app.models",
defaultSceneName = "MainScene",
}

for k, v in pairs(configs or {}) do
self.configs_[k] = v
end

if type(self.configs_.viewsRoot) ~= "table" then
self.configs_.viewsRoot = {self.configs_.viewsRoot}
end
if type(self.configs_.modelsRoot) ~= "table" then
self.configs_.modelsRoot = {self.configs_.modelsRoot}
end

if DEBUG > 1 then
dump(self.configs_, "AppBase configs")
end

if CC_SHOW_FPS then
cc.Director:getInstance():setDisplayStats(true)
end

-- event
self:onCreate()
end

function AppBase:run(initSceneName)
initSceneName = initSceneName or self.configs_.defaultSceneName
self:enterScene(initSceneName)
end

function AppBase:enterScene(sceneName, transition, time, more)
local view = self:createView(sceneName)
view:showWithScene(transition, time, more)
return view
end

function AppBase:createView(name)
for _, root in ipairs(self.configs_.viewsRoot) do
local packageName = string.format("%s.%s", root, name)
local status, view = xpcall(function()
return require(packageName)
end, function(msg)
if not string.find(msg, string.format("'%s' not found:", packageName)) then
print("load view error: ", msg)
end
end)
local t = type(view)
if status and (t == "table" or t == "userdata") then
return view:create(self, name)
end
end
error(string.format("AppBase:createView() - not found view \"%s\" in search paths \"%s\"",
name, table.concat(self.configs_.viewsRoot, ",")), 0)
end

function AppBase:onCreate()
end

return AppBase
在前面的分析中知道main.lua是执行的是App的run函数,作为基类的AppBase,当然也要被调用run函数,因此直接看run函数:主要是创建并进入场景initSceneName,如果run的参数没有指定开始的场景则使用默认场景defaultSceneName,默认场景在构造函数的时候被初始化为MainScene,也就是说场景默认将从MainScene开始。

如果给run指定了场景名(字符串),那么项目启动后会直接进入该场景,这点有个好处是如果要调试设计某场景可以直接从这个场景进入,不必从其他场景进入了。也就是在main.lua中这么调用即可:
local function main()
require("app.MyApp"):create():run('PlayScene')
end
那么项目启动后会直接进入PlayScene场景,而不再是默认的MainScene场景。

我们现在不做改动,仍然接着默认流程分析, MainScene为主场景, 创建并显示一张背景图,创建显示一个“Play”按钮,按钮的点击事件是进入PlayScene场景。

local  MainScene  class ( "MainScene" cc . load ( "mvc" ). ViewBase )
function MainScene:onCreate()
-- add background image
display.newSprite("MainSceneBg.jpg")
:move(display.center)
:addTo(self)

-- add play button
local playButton = cc.MenuItemImage:create("PlayButton.png", "PlayButton.png")
:onClicked(function()
self:getApp():enterScene("PlayScene")
end)
cc.Menu:create(playButton)
:move(display.cx, display.cy - 200)
:addTo(self)
end

return MainScene


PlayScene场景:
local PlayScene = class("PlayScene", cc.load("mvc").ViewBase)

local GameView = import(".GameView")

function PlayScene:onCreate()
-- create game view and add it to stage
self.gameView_ = GameView:create()
:addEventListener(GameView.events.PLAYER_DEAD_EVENT, handler(self, self.onPlayerDead))
:start()
:addTo(self)
end

function PlayScene:onPlayerDead(event)
-- add game over text
local text = string.format("You killed %d bugs", self.gameView_:getKills())
cc.Label:createWithSystemFont(text, "Arial", 96)
:align(display.CENTER, display.center)
:addTo(self)

-- add exit button
local exitButton = cc.MenuItemImage:create("ExitButton.png", "ExitButton.png")
:onClicked(function()
self:getApp():enterScene("MainScene")
end)
cc.Menu:create(exitButton)
:move(display.cx, display.cy - 200)
:addTo(self)
end

return PlayScene
PlayScene场景创建游戏逻辑视图GameView并调用start函数开始游戏,绑定了一个游戏结束的事件,这个事件会在GameView中在触发游戏结束逻辑时发生,PlayScene由于绑定了该事件,则会在游戏结束时调用其绑定的回调事件,以显示战绩和分数,显示一个退出按钮,退出按钮事件为进入MainScene场景。

至此,场景的切换已经很清晰了,那么主要的游戏逻辑便是在GameView中了。

打开工程根目录下的配置文件config.json:
{
"init_cfg": {
"isLandscape": true,
"isWindowTop": false,
"name": "redDefense",
"width": 1920,
"height": 1080,
"entry": "src/main.lua",
"consolePort": 6050,
"uploadPort": 6060,
"debugPort": 10000,
"forwardConsolePort": 10089,
"forwardUploadPort": 10091
},
"simulator_screen_size": [
{
"title": "iPhone 3Gs (480x320)",
"width": 480,
"height": 320
},
{
"title": "iPhone 4 (960x640)",
"width": 960,
"height": 640
},
{
"title": "iPhone 5 (1136x640)",
"width": 1136,
"height": 640
},
{
"title": "iPad (1024x768)",
"width": 1024,
"height": 768
},
{
"title": "iPad Retina (2048x1536)",
"width": 2048,
"height": 1536
},
{
"title": "Android (800x480)",
"width": 800,
"height": 480
},
{
"title": "Android (854x480)",
"width": 854,
"height": 480
},
{
"title": "Android (1280x720)",
"width": 1280,
"height": 720
},
{
"title": "Android (1920x1080)",
"width": 1920,
"height": 1080
}
]
}
可以看到 "entry": "src/main.lua",也就是说入口文件是main.lua,进而打开main.lua:
cc.FileUtils:getInstance():setPopupNotify(false)
cc.FileUtils:getInstance():addSearchPath("src/")
cc.FileUtils:getInstance():addSearchPath("res/")

require "config"
require "cocos.init"

local function main()
require("app.MyApp"):create():run()
end

local status, msg = xpcall(main, __G__TRACKBACK__)
if not status then
print(msg)
end
执行main函数,main函数里加载MyApp创建并运行,进而打开MyApp.lua:
local MyApp = class("MyApp", cc.load("mvc").AppBase)

function MyApp:onCreate()
math.randomseed(os.time())
end

return MyApp
这里就有点看头,MyApp仅仅是继承自AppBase,onCreate函数只是初始化了下随机数种子,也就意味着更多的操作在AppBase中,我们打开分析:
local AppBase = class("AppBase")

function AppBase:ctor(configs)
self.configs_ = {
viewsRoot = "app.views",
modelsRoot = "app.models",
defaultSceneName = "MainScene",
}

for k, v in pairs(configs or {}) do
self.configs_[k] = v
end

if type(self.configs_.viewsRoot) ~= "table" then
self.configs_.viewsRoot = {self.configs_.viewsRoot}
end
if type(self.configs_.modelsRoot) ~= "table" then
self.configs_.modelsRoot = {self.configs_.modelsRoot}
end

if DEBUG > 1 then
dump(self.configs_, "AppBase configs")
end

if CC_SHOW_FPS then
cc.Director:getInstance():setDisplayStats(true)
end

-- event
self:onCreate()
end

function AppBase:run(initSceneName)
initSceneName = initSceneName or self.configs_.defaultSceneName
self:enterScene(initSceneName)
end

function AppBase:enterScene(sceneName, transition, time, more)
local view = self:createView(sceneName)
view:showWithScene(transition, time, more)
return view
end

function AppBase:createView(name)
for _, root in ipairs(self.configs_.viewsRoot) do
local packageName = string.format("%s.%s", root, name)
local status, view = xpcall(function()
return require(packageName)
end, function(msg)
if not string.find(msg, string.format("'%s' not found:", packageName)) then
print("load view error: ", msg)
end
end)
local t = type(view)
if status and (t == "table" or t == "userdata") then
return view:create(self, name)
end
end
error(string.format("AppBase:createView() - not found view \"%s\" in search paths \"%s\"",
name, table.concat(self.configs_.viewsRoot, ",")), 0)
end

function AppBase:onCreate()
end

return AppBase
在前面的分析中知道main.lua是执行的是App的run函数,作为基类的AppBase,当然也要被调用run函数,因此直接看run函数:主要是创建并进入场景initSceneName,如果run的参数没有指定开始的场景则使用默认场景defaultSceneName,默认场景在构造函数的时候被初始化为MainScene,也就是说场景默认将从MainScene开始。

如果给run指定了场景名(字符串),那么项目启动后会直接进入该场景,这点有个好处是如果要调试设计某场景可以直接从这个场景进入,不必从其他场景进入了。也就是在main.lua中这么调用即可:
local function main()
require("app.MyApp"):create():run('PlayScene')
end
那么项目启动后会直接进入PlayScene场景,而不再是默认的MainScene场景。

我们现在不做改动,仍然接着默认流程分析, MainScene为主场景, 创建并显示一张背景图,创建显示一个“Play”按钮,按钮的点击事件是进入PlayScene场景。

local  MainScene  class ( "MainScene" cc . load ( "mvc" ). ViewBase )
function MainScene:onCreate()
-- add background image
display.newSprite("MainSceneBg.jpg")
:move(display.center)
:addTo(self)

-- add play button
local playButton = cc.MenuItemImage:create("PlayButton.png", "PlayButton.png")
:onClicked(function()
self:getApp():enterScene("PlayScene")
end)
cc.Menu:create(playButton)
:move(display.cx, display.cy - 200)
:addTo(self)
end

return MainScene


PlayScene场景:
local PlayScene = class("PlayScene", cc.load("mvc").ViewBase)

local GameView = import(".GameView")

function PlayScene:onCreate()
-- create game view and add it to stage
self.gameView_ = GameView:create()
:addEventListener(GameView.events.PLAYER_DEAD_EVENT, handler(self, self.onPlayerDead))
:start()
:addTo(self)
end

function PlayScene:onPlayerDead(event)
-- add game over text
local text = string.format("You killed %d bugs", self.gameView_:getKills())
cc.Label:createWithSystemFont(text, "Arial", 96)
:align(display.CENTER, display.center)
:addTo(self)

-- add exit button
local exitButton = cc.MenuItemImage:create("ExitButton.png", "ExitButton.png")
:onClicked(function()
self:getApp():enterScene("MainScene")
end)
cc.Menu:create(exitButton)
:move(display.cx, display.cy - 200)
:addTo(self)
end

return PlayScene
PlayScene场景创建游戏逻辑视图GameView并调用start函数开始游戏,绑定了一个游戏结束的事件,这个事件会在GameView中在触发游戏结束逻辑时发生,PlayScene由于绑定了该事件,则会在游戏结束时调用其绑定的回调事件,以显示战绩和分数,显示一个退出按钮,退出按钮事件为进入MainScene场景。

至此,场景的切换已经很清晰了,那么主要的游戏逻辑便是在GameView中了。
### Vue项目中使用vue-video-player播放M3U8视频文件时遇到的播放失败解决方案 为了成功在Vue项目中通过`vue-video-player`组件播放M3U8格式的视频,需确保已正确配置并引入必要的依赖库。由于单独的`vue-video-player`并不直接支持M3U8格式,因此还需要额外安装`videojs-contrib-hls`来提供HLS协议的支持[^1]。 #### 安装必要依赖包 首先,在命令行工具中执行如下npm指令以安装所需的软件包: ```bash npm install video.js vue-video-player videojs-contrib-hls --save ``` 这一步骤会下载并保存`video.js`, `vue-video-player`以及专门用于处理HLS流媒体传输的插件`videojs-contrib-hls`到项目的node_modules目录下。 #### 配置Video Player选项 接着,在Vue组件内部定义好`playerOptions`属性,指定要使用播放源及其类型为application/x-mpegURL(即M3U8)。同时,记得给定其他可能影响正常工作的参数设置,比如自动播放(`autoplay`)、循环播放(`loop`)等特性开关。 ```javascript data() { return { playerOptions: { autoplay: false, loop: true, controls: true, // 显示控制条 sources: [{ src: 'https://yourdomain.com/path/to/playlist.m3u8', type: "application/x-mpegURL" }], techOrder: ["html5", "flash"], flash: { hls: { withCredentials: false } }, html5: { hls: { overrideNative: true }} } }; } ``` 上述代码片段中的`src`字段应替换为目标M3U8文件的实际网络地址;而`techOrder`数组指定了优先采用的技术栈顺序——这里设为首选HTML5技术实现播放功能,并启用覆盖原生浏览器行为的功能以便更好地兼容不同设备上的表现差异。 #### HTML模板部分 最后,在.vue文件内的template标签里加入对应的<video-player>标记符,绑定之前准备好的`playerOptions`对象作为其`:options`属性值即可完成基本布局构建工作。 ```html <template> <div id="app"> <!-- Video Player --> <video-player class="vjs-custom-skin" :options="playerOptions"></video-player> </div> </template> <script> // 导入相关模块... import { videoPlayer } from 'vue-video-player' export default { name: 'App', components: { videoPlayer }, data(){ ... } }; </script> ``` 以上操作完成后重新启动开发服务器测试页面效果,如果一切顺利的话应该能够看到可以正常加载和播放M3U8资源的多媒体控件了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值