2015年的眾多HTML5(以下簡稱H5)游戲當中,有個別游戲以超高的月流水向大眾展示了其在未來游戲行業中不可限量的發展趨勢。2015年4月,《愚公移山》以月流水超100萬的成績拔得頭籌引起業界關注后,《傳奇世界》H5上線3個月月流水就破了1500萬。而今年2月14日情人節刷爆朋友圈的《曬結婚證》H5更是驗證了移動網頁游戲是如何利用碎片化的時間贏得市場的。
盡管如此,H5也并非像市場吹噓的那樣樂觀。DataEye《2015年中國移動游戲行業年度報告》顯示,截止到2015年底,H5游戲數量超過3000款,盡管發展態勢樂觀毋庸置疑,但是2015年的H5游戲市場未如年初預言那般迎來所謂的爆發。也就是說H5的現狀就是千軍萬馬過獨木橋,大部分還是未能踏上橋就被出局。
因此有業內人士就表示,不管是類型和玩法的豐富性,還是游戲內容的體驗,H5游戲都存在很大不足,因此手機用戶的真實導入量長期處于很低的水平。那么面對美麗泡沫般的H5游戲,在除去好的產品技術外,更應該在渠道上下功夫了。
瀏覽器
以UC瀏覽器、QQ瀏覽器、手機百度為代表的瀏覽器渠道,是目前大部分H5游戲的主要流量來源,在所有流量來源中占比50%。
因此H5游戲廠商就需要根據瀏覽器的屬性去調整,例如在《傳奇世界》H5渠道推廣中,瀏覽器的ARPU值高,大R用戶多。而玩吧要做小付費,游戲就針對它開了2元、6元的小付費,ARPU值不高,但付費率高,用戶短平快。
微信朋友圈KOL
2014-2015年,多數耳熟能詳H5游戲均出自朋友圈傳播,如《圍住神經貓》、《打企鵝》、《找房祖名》、《貂蟬有妖氣》、《時尚都市》、《來消星星的你》等爆款,因此,朋友圈被譽為最早的H5推廣的溫床。
雖然它被公認為最適合在微信平臺上傳播,但是在之前《神經貓》取得大火之后,基于對產品體驗的考慮,微信朋友圈對于H5游戲的分享進行了流量管制,微信平臺過了10萬、20萬就可能被封掉了。而隨后再也沒有出現過像《神經貓》那樣大范圍傳播的H5游戲,直到《曬結婚證》H5的出現火了一整天也難逃被封的厄運。
盡管如此,朋友圈依然是適用于H5推廣的一個渠道,因此不能因為限制就畏手畏腳,找到一個好的契合點,與用戶行為習慣都相吻合,制造出更多的KOL才能將品牌打入用戶手中,反過來說,一旦火爆被封,也可以在中轉、跳轉做一些調整,然后在一個時間節點上取消引導關注。
APP
去年包括滴滴、萬能鑰匙Wifi在內的多個超級APP開始嘗試HTML5游戲的推廣,不過在實際操作中的轉換和留存率表現較為一般。
然而盡管目前長尾的流量型APP為HTML5游戲帶來的流量并不高,但卻是最具發展潛力的渠道類型。比如5秒輕游戲推出的APP游戲化運營解決方案,就快速為大量APP提供了“輕游戲+輕社交”的HTML5內容入口。
因此未來HTML5游戲渠道將出現定制化的游戲生態。以滴滴為例,開發商可通過針對打車優惠卷和周邊禮品互動等內容進行相關推薦,從而引導和擴大用戶需求。
傳統游戲平臺
像是5秒輕游戲、4399、手機小游戲、中國電信愛游戲、火舞游戲、1758等傳統線上分發渠道,相較于在原生手游市場的呼風喚雨,線上分發平臺目前對HTML5游戲的分發并不盡如人意,只占整個市場的20%。因此多數H5不選用這樣的推廣渠道與手游端游去PK。但如果有強IP做支撐,這樣的平臺再合適不過了。
媒體及公眾號推廣
H5游戲在新聞媒體上發消息需要的就是耐心,專業的媒體渠道必不可少,這是游戲品牌建設的基本保障,比如一個H5在媒體投放廣告,一開始可能只有千個新增用戶,收入不高,但媒體投放持續幾個月后達到曝光,就會收入就會翻幾倍,這時需要考慮的因素就很多了,比如廣告素材,活動要跟上以及細致經營等。
公號的推廣就是軟文的形式,大V的領導作用也是有目共睹,雖然近些年對于大V粉絲作假的說法時有發生,但是即使只有千分之一的真粉,他們也能一石激起千層浪。
目前H5游戲分發渠道有上百家,這里只是簡單介紹了用處最多的五種。而未來渠道整合一定是H5游戲線上分發過程中最重要的環節。因此,從多年來驗證過的互聯網三種盈利模式看,H5游戲的推廣一是以上述廣告營銷渠道為主,二是電商類的一些合作也可能會在今年快速推進。
微信ID:yxhygc1
長按二維碼關注我
薦:使用NSDT 編輯器快速搭建3D應用場景
大多數 3D 對象是 使用建模工具創建,這是有充分理由的。創建復雜對象 (如飛機甚至建筑物)很難在代碼中完成。建模工具 幾乎總是有意義的,但也有例外!其中之一可能是案例 就像飛行拱廊島連綿起伏的丘陵一樣。我們最終使用了 我們發現更簡單,甚至可能更直觀的技術:一個 高度圖。
高度圖是一種 使用常規二維圖像來描述 像島嶼或其他地形一樣的表面。這是一種非常常見的使用方式 高程數據,不僅在游戲中,而且在地理信息系統中 制圖師和地質學家使用的 (GIS)。
幫助您獲得想法 有關其工作原理,請查看此交互式演示中的高度圖。嘗試繪圖 ,然后檢出生成的地形。
高度圖背后的概念 很簡單。在上圖所示的圖像中,純黑色是 “地板”和純白色是最高峰。介于兩者之間的灰度顏色 表示相應的高程。這為我們提供了 256 個海拔高度,這 是我們游戲的大量細節。實際應用程序可能會使用完整的 色譜可存儲更多層次的細節(2564 = 4,294,967,296 級 詳細信息(如果包含 Alpha 通道)。
高度圖有幾個 與傳統多邊形網格相比的優勢:
一、高度圖很多 更緊湊。僅存儲最重要的數據(高程)。它 需要以編程方式轉換為 3D 對象,但這是 經典交易:您現在節省空間,稍后通過計算付款。通過存儲 數據即圖像,您將獲得另一個空間優勢:您可以利用標準 圖像壓縮技術并使數據變小(相比之下)!
其次,高度圖是一個 生成、可視化和編輯地形的便捷方式。非常直觀 當你看到一個。感覺有點像看地圖。這被證明是 對飛行街機特別有用。我們設計和編輯了我們的島嶼 在 Photoshop 中!這使得根據需要進行小調整變得非常簡單。 例如,當我們想確保跑道完全平坦時, 我們只是確保以單一顏色在該區域上繪畫。
您可以看到高度圖 下面的飛行拱廊。看看你是否能發現我們為 跑道和村莊。
飛行街機島的高度圖。它是在Photoshop中創建的,它基于著名的太平洋島鏈中的“大島”。有什么猜測嗎?
在解碼高度貼圖后映射到生成的 3D 網格上的紋理。更多內容見下文。
我們用Babylon.js建造了飛行拱廊,Babylon給了我們一個漂亮的 從高度圖到 3D 的簡單路徑。Babylon提供了一個 API 來生成 來自高度圖圖像的網格幾何體:
ar ground = BABYLON.Mesh.CreateGroundFromHeightMap(
'your-mesh-name',
'/path/to/heightmap.png',
100, // width of the ground mesh (x axis)
100, // depth of the ground mesh (z axis)
40, // number of subdivisions
0, // min height
50, // max height
scene,
false, // updateable?
null // callback when mesh is ready
);`
細節量是 由該細分的財產決定。需要注意的是, 參數是指高度圖兩側的細分數量 圖像,而不是單元格總數。所以稍微增加這個數字可以 對網格中的頂點總數有很大影響。
在下一節中,我們將 了解如何為地面設置紋理,但在嘗試使用高度貼圖時 創建時,查看線框很有用。這是應用簡單代碼 線框紋理,因此很容易看到高度圖數據是如何轉換為的 網格的頂點:
// simple wireframe material
var material = new BABYLON.StandardMaterial('ground-material', scene);
material.wireframe = true;
ground.material = material;`
一旦我們有一個模型,映射一個 質地相對簡單。對于飛行街機,我們簡單地創建了一個 非常大的圖像,與我們的高度圖中的島嶼相匹配。圖像得到 延伸到地形的輪廓上,所以紋理和高度圖 保持相關性。這真的很容易想象,再一次,所有 制作工作是在Photoshop中完成的。
原始紋理圖像是 創建于 4096x4096。那可是挺大的!(我們最終將尺寸減小了 為了保持下載合理,級別到2048x2048,但所有 使用全尺寸圖像進行開發。這是來自 原始紋理。
原始島嶼紋理的全像素示例。整個城鎮只有大約300平方像素。
這些矩形表示 島上城鎮的建筑。我們很快注意到 我們可以在地形和 其他 3D 模型。即使使用我們巨大的島嶼紋理,區別在于 令人分心的明顯!
為了解決這個問題,我們“混合” 以隨機噪聲的形式進入地形紋理的附加細節。您可以 請參閱下面的之前和之后。注意額外的噪點如何增強外觀 地形細節。
我們創建了一個自定義著色器 添加噪音。著色器為您提供了對 WebGL 3D 場景的渲染,這是著色器如何 有用。
WebGL著色器由兩個組成 主要部分:頂點和片段著色器。頂點的主要目標 著色器是將頂點映射到渲染幀中的某個位置。片段(或 像素)著色器控制像素的結果顏色。
著色器是用 稱為GLSL(圖形庫著色器語言)的高級語言,它 類似于C。此代碼在 GPU 上執行。深入了解如何 著色器工作,請參閱此處 有關如何為 Babylon.js 創建自己的自定義著色器的教程,或參閱此圖形著色器編碼初學者指南。
我們不會改變我們的 紋理映射到地面網格體,因此我們的頂點著色器非常簡單。 它只是計算標準映射并分配目標位置。
precision mediump float;
// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
// Uniforms
uniform mat4 worldViewProjection;
// Varying
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
void main() {
vec4 p = vec4( position, 1.0 );
vPosition = p;
vNormal = normal;
vUV = uv;
gl_Position = worldViewProjection * p;
}
我們的片段著色器有點 更復雜。它結合了兩個不同的圖像:基礎圖像和混合圖像。 基礎圖像映射到整個地面網格。在飛行街機中,這個 是島嶼的彩色圖像。混合圖像是使用的小噪點圖像 在近距離為地面提供一些紋理和細節。著色器 組合每個圖像中的值以創建跨 島。
飛行的最后一課 街機發生在有霧的日子,所以我們的像素著色器的另一個任務是 調整顏色以模擬霧。調整基于頂點的距離 來自相機,遠處像素被“遮擋”得更厲害 在霧中。您將在函數中看到此距離計算 在主著色器代碼上方。calcFogFactor
// #ifdef GL_ES
precision highp float;
// #endif
uniform mat4 worldView;
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
// Refs
uniform sampler2D baseSampler;
uniform sampler2D blendSampler;
uniform float blendScaleU;
uniform float blendScaleV;
// #define FOGMODE_NONE 0.
// #define FOGMODE_EXP 1.
// #define FOGMODE_EXP2 2.
// #define FOGMODE_LINEAR 3.
// #define E 2.71828
uniform vec4 vFogInfos;
uniform vec3 vFogColor;
float calcFogFactor() {
// gets distance from camera to vertex
float fogDistance = gl_FragCoord.z / gl_FragCoord.w;
float fogCoeff = 1.0;
float fogStart = vFogInfos.y;
float fogEnd = vFogInfos.z;
float fogDensity = vFogInfos.w;
if (FOGMODE_LINEAR == vFogInfos.x) {
fogCoeff = (fogEnd - fogDistance) / (fogEnd - fogStart);
}
else if (FOGMODE_EXP == vFogInfos.x) {
fogCoeff = 1.0 / pow(E, fogDistance * fogDensity);
}
else if (FOGMODE_EXP2 == vFogInfos.x) {
fogCoeff = 1.0 / pow(E, fogDistance * fogDistance * fogDensity * fogDensity);
}
return clamp(fogCoeff, 0.0, 1.0);
}
void main(void) {
vec4 baseColor = texture2D(baseSampler, vUV);
vec2 blendUV = vec2(vUV.x * blendScaleU, vUV.y * blendScaleV);
vec4 blendColor = texture2D(blendSampler, blendUV);
// multiply type blending mode
vec4 color = baseColor * blendColor;
// factor in fog color
float fog = calcFogFactor();
color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
gl_FragColor = color;
}
我們定制的最后一件作品 Blend shader 是 Babylon 使用的 JavaScript 代碼。主要目的 此代碼用于準備傳遞給頂點和像素著色器的參數。
function BlendMaterial(name, scene, options) {
this.name = name;
this.id = name;
this.options = options;
this.blendScaleU = options.blendScaleU || 1;
this.blendScaleV = options.blendScaleV || 1;
this._scene = scene;
scene.materials.push(this);
var assets = options.assetManager;
var textureTask = assets.addTextureTask('blend-material-base-task', options.baseImage);
textureTask.onSuccess = _.bind(function(task) {
this.baseTexture = task.texture;
this.baseTexture.uScale = 1;
this.baseTexture.vScale = 1;
if (options.baseHasAlpha) {
this.baseTexture.hasAlpha = true;
}
}, this);
textureTask = assets.addTextureTask('blend-material-blend-task', options.blendImage);
textureTask.onSuccess = _.bind(function(task) {
this.blendTexture = task.texture;
this.blendTexture.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE;
this.blendTexture.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE;
}, this);
}
BlendMaterial.prototype = Object.create(BABYLON.Material.prototype);
BlendMaterial.prototype.needAlphaBlending = function () {
return (this.options.baseHasAlpha === true);
};
BlendMaterial.prototype.needAlphaTesting = function () {
return false;
};
BlendMaterial.prototype.isReady = function (mesh) {
var engine = this._scene.getEngine();
// make sure textures are ready
if (!this.baseTexture || !this.blendTexture) {
return false;
}
if (!this._effect) {
this._effect = engine.createEffect(
// shader name
"blend",
// attributes describing topology of vertices
[ "position", "normal", "uv" ],
// uniforms (external variables) defined by the shaders
[ "worldViewProjection", "world", "blendScaleU", "blendScaleV", "vFogInfos", "vFogColor" ],
// samplers (objects used to read textures)
[ "baseSampler", "blendSampler" ],
// optional define string
"");
}
if (!this._effect.isReady()) {
return false;
}
return true;
};
BlendMaterial.prototype.bind = function (world, mesh) {
var scene = this._scene;
this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
this._effect.setColor3("vFogColor", scene.fogColor);
this._effect.setMatrix("world", world);
this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
// Textures
this._effect.setTexture("baseSampler", this.baseTexture);
this._effect.setTexture("blendSampler", this.blendTexture);
this._effect.setFloat("blendScaleU", this.blendScaleU);
this._effect.setFloat("blendScaleV", this.blendScaleV);
};
BlendMaterial.prototype.dispose = function () {
if (this.baseTexture) {
this.baseTexture.dispose();
}
if (this.blendTexture) {
this.blendTexture.dispose();
}
this.baseDispose();
};
Babylon.js使它變得容易 創建基于著色器的自定義材質。我們的混合材料相對簡單, 但它確實對島嶼的外觀產生了很大的影響,當 飛機低空飛到地面。著色器將 GPU 的強大功能帶到 瀏覽器,擴展可應用于 3D 的創意效果類型 場景。在我們的案例中,這是畫龍點名!
原文鏈接:使用 WebGL 為 HTML5 游戲創建逼真的地形
為一名HTML5游戲開發者,
你還在為如何絞盡腦汁也玩不轉命令行而憤恨嗎?
你還在為無法及時預覽自己所編輯的UI效果而苦惱嗎?
你還在為翻來覆去進行繁瑣的調試流程而糾結嗎?
你還在為同時在幾個工具之間切換編輯而混亂嗎?
此時,你是不是特別渴望一款全功能集成開發工具呢?
白鷺Egret Wing2.0恰逢其時地出現,為開發者帶來移動游戲開發一站式解決方案。
Egret Wing2.0是什么?
Egret Wing2.0是一款針對Egret項目的集成開發環境,通過可視化方式創建、編輯和管理項目中所有游戲用戶界面,并同時進行TS代碼編寫和斷點調試。
(經過全新的升級,Egret Wing2.0給開發者帶來更加高效便捷的開發環境)
為什么選擇Egret Wing2.0?
1. 工具體積精簡,用戶體驗更流暢。
內存占用小,代碼提示快:由于Egret Wing 2.0是為Egret項目深度定制并全部自主研發,省去其他不必要功能,故內存占用小,代碼提示速度也高于基于Eclipse等大型工具定制的同類型產品。
加載速度快,體驗流暢:由于針對性強,不依賴第三方大型開源工具,沒有不必要的額外啟動選項,所以加載速度更快,增強了用戶體驗流暢性。
2. 即時錯誤提示
在編譯之前就可即時發現代碼中的語法語義錯誤,并實時反饋錯誤代碼位置和原因,以便開發者能夠快速修改。
3. 全功能代碼編輯器
作為一款全功能的集成開發環境,向開發者提供智能代碼提示。
代碼提示精準:即時提示可能要輸入的類、方法或變量等,更容易看到選擇部分的注釋內容,提高代碼編寫速度和準確率。
懸浮注釋提示:通過鼠標懸浮的方式,快速查看指定內容處注釋。
智能代碼定位:相同類型的類、對象、屬性的高亮標記,便于開發者快速定位其在程序文件中的位置。
4. 強大的debug能力
Egret Wing2.0面向開發者提供了強大的無縫調試能力。
一鍵調試:一鍵啟動調試功能,方便快捷地在工具內調試Egret游戲和應用。
TypeScript腳本斷點調試:無需任何配置直接在TS源代碼上設置斷點調試TS代碼。
5.可視化編輯UI
Egret Wing 提供的全局可視化UI編輯界面。
全程可視化編輯:通過可視化的方式直接拖拽和編輯UI皮膚屬性,全程傻瓜式操作,免去寫代碼的煩惱。
可視化編輯UI動畫效果:新增動畫面板,以時間軸方式可視化操作UI組件,制作出不同動畫效果,并可在預覽模式中直接查看效果。
Egret Wing2.0的使用效果如何?
Egret Wing2.0終于讓我告別命令行時代,自動編譯項目,直接在瀏覽器中刷新就可以查看效果。同時,皮膚制作和代碼編輯都在同一個工具中進行,不需要在幾個工具之間來回切換。此外,直接在TS中進行代碼調試,大大縮減到瀏覽器中調試的時間成本。
——某白鷺游戲開發者
如何獲取Egret Wing2.0?
6月8日以后,歡迎廣大開發者直接通過白鷺引擎面板更新到 Egret Wing2.0版,即可體驗各種酷爽功能。
如對Egret Wing2.0有任何疑問?
如針對Egret Wing2.0版本有任何疑問,歡迎大家掃描下面二維碼關注微信服務號“白鷺引擎開發者服務平臺”,白鷺技術服務團隊將為你答疑解惑。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。