随着智能终端和移动互联网的高速发展,客户端游戏和客户端网游的发展开始放缓,为了迎合人们现在碎片化时间的发展趋势,各大游戏巨头企业将目光投向了手机游戏市场,与移动互联网的高速发展共同前进。
机遇
在智能手机发展初期,市场上主流的操作系统是Symbian S60和Lunix,受当时手机硬件、性能、物理屏幕和系统智能程度等多方面因素,当时手机游戏的可玩性极低,与同时代的掌上游戏机相比,各方面均有极大的差距。在智能手机发展初期,手机游戏并没有引起游戏巨头与终端厂商的重视。
在iPhone发售之后,手机游戏进入一个新的发展阶段,iPhone在性能方面与同时代的掌上游戏机相比并不差,但由于游戏厂商对手机游戏的不重视,始终没有颠覆性的手游大作面世。
从2008年开始,Android系统的发布,iPhone的新产品发售,优秀的系统构架,强大的终端性能,开始让部分游戏厂商对移动端游戏的开发重视起来,并且在iOS和Android平台开发游戏的团队逐渐强大起来。
随着iPhone的快速兴起,iPhone时尚的设计理念也开始极受追捧,导致智能手机的按键越来越少,传统的导航键也逐渐消失。这对当时的手机游戏是极大的打击,用户的使用习惯没有经过合理的过度,游戏厂商对游戏的开发速度低于手机的进化频率,导致那一时期的用户对手机游戏体验极差,诸多经典游戏在移植到移动端后,并没有取得预期的成功。
发展
在2012年,愤怒的小鸟和植物大战僵尸在登陆手机平台后,在全球范围内均引起了强烈的反响,位列各大下载排行榜前几位。这两款游戏的画面制作精良,游戏可玩性极高,最重要的是,这两款游戏在触摸屏上的完美操作使用户获得完美体验。这两款游戏的成功无疑为手机游戏市场取得了强大的自信,且使众多厂商重拾了对手机游戏市场的信心。
在此之后,众多游戏厂商开始对手机游戏在触摸屏上的操控优化,且再次尝试将经典游戏移植到移动端,但大部分经过操控优化的手机游戏仍然没能在市场中得到良好的口碑。其关键原因在于游戏的操控完美,但对游戏的可玩性、游戏原有的游戏感等多方面大打折扣。游戏厂商将经历一心扑在游戏操控上,但忽略了游戏是否适合触摸屏,是否适合移植到移动端,什么样的触屏操控是可提升游戏的可玩性等关键因素。
在游戏厂商对手机游戏的不断摸索,对手机游戏的理解不断深化,手机游戏逐渐进入高速发展期,越来越多的高质量手机游戏开始在市场中出现,手机市场呈现一片繁荣的景象,且高质量用户在不断扩大。
困难
手机游戏市场的发展正在不断提速,智能手机的性能已经非常强大,但手机游戏的发展仍存在一个致命的障碍,就是智能手机的续航能力。高性能的处理器,越来越大的物理屏幕,越来越多的手机功能,都再最大程度的消耗着手机电池的容量极限。
游戏行业的高利润值,手机游戏市场的快速成长,对游戏市场巨头企业的关注度也具有极大的吸引力。巨头纷纷进入手机游戏市场。但是,这些巨头企业在手机游戏市场业务开展并没有能够顺风顺水。
游戏巨头企业在手机游戏市场中发展,最大的障碍是无法适应移动互联网市场的市场规则,而是套用在互联网市场的已有经验,但并不足以在市场中立足。
这些企业巨头在端游市场打拼多年,在市场中已具有极大的优势,且在游戏定位、游戏体验、游戏理解等多方面已具有自己的一套成型的模式,但这些对于手机游戏并不适用,甚至有可能成为在手机游戏市场发展的包袱。另一方面,大部分公司在研发、运营、营销等各环节实行一体化,而这些在移动互联网市场都是不适用的,手机游戏市场在研发和运营是独立的,且分工明确。
这些巨头企业在端游市场打拼多年,对游戏的理解、游戏的深度挖掘、游戏的行业经验是这些企业进入手机游戏市场的天生优势,如果这些巨头企业放下在端游市场的固有观念,而重新制定一套适合与移动互联网、移动端的游戏理念,在手机游戏市场仍有很大的潜力,且仍有可能成为该市场的领军者。
挑战
在中国市场中,端游巨头发展手机游戏业务,在抛开自身的发展障碍外,还有一些外部因素同样阻碍着国内手机游戏市场的发展。
移动网络的网络环境,是制约手机网游的最大障碍,信号覆盖面、移动互联网带宽、WiFi点的普及、3G/4G的发展速度等,均成为手机网游的制约条件。另一方面,大型手机网游的读取速度、读取所耗费的流量等同样影响着用户的游戏体验。对于手机游戏市场,无法满足用户的游戏体验,会使用户大量流失。随着移动互联网的不断升级,该问题会被解决。但在现阶段,企业仍需通过其他方式将该障碍跨越。
另一方面,市场中手机品牌、型号繁多,高中低端手机的性能、屏幕分辩率均存在差异,同样一款游戏在不同的手机中运行,用户所得到的用户体验也是不同的。如游戏对手机性能要求过高,则中低端手机用户的体验则会相对较差,游戏的受众则会相对小众。而针对不同屏幕分辩率而开发多个适配版本,会使厂商的开发成本大大增加。
在手机操作系统方面,不断地更新换代,对厂商同样是一个极大地挑战,从一个系统向另一个系统转移,对厂商的资源、成本等是极大地浪费。在开发经验同样面临着一次重新的积累。
游戏企业在手机游戏市场的发展面临着不少障碍,但厂商必须迎难而上,市场不会因为任何一个厂商的不作为而停滞。作为该市场的多变性,厂商也需要尽快适应,移动互联网本就是一个多变的市场,如果厂商无法及时适应移动互联网的变化,该厂商终究会被市场淘汰,而另一个行业巨头将会崛起。
参考推荐:
各大厂商进军手游市场 机遇与困难并存
沃森先生所说的 “巨型电脑”已经不是幻想,现在已经实现:它是通过网络将更多的运算能力、存储能力和网络资源大规模集成。你的个人电脑CPU可能具有双核或四核,而“巨型电脑”中的主机, 每台都支持支持几个甚至几十个多核处理器,重要的是云中这样的主机有许多台,它们的处理器可能是不同型号、不同构架,甚至是采用不同的“语言”(指令集);你的个人电脑可能拥有几百GB或几个TB的磁盘,而“巨型电脑”中的存储空间动辄几千TB,而且可以随时扩展、更换,并且做好了完备的数据备份,让所有数据都万无一失。这样的“巨型电脑”,现在被称之为 “云计算”。
在拥有了强大运算性能和海量存储容量的同时,问题也随之而来——如何来管理这样一台集合了成百上千台计算机的“巨型电脑”呢?比如气象部门需要保存一段时间某地区的所有气象数据,一台主机硬盘装不下,却又必须保持数据的连续和完整;比如在一台主机上部署一个小型网站,处理器只用到很小的负载就可以胜任,大多数内核都在闲置。
能力越大,责任越大,要管好这样一台“巨型电脑”,最好的方式就是“虚拟化”。简单地说,通过虚拟化技术,你可以不考虑“巨型电脑”有多少台不同型号的主机,它可以将所有主机的处理器、存储装置、网络等I/O接口抽象出来,像操作一台个人电脑一样便捷。
【“虚拟顾问团”,真正的优化大师】
比“云计算”的概念产生早30多年,早在20世纪60年代,大型机的鼻祖IBM公司就开始着实施虚拟化技术。现在,IBM公司的基于IBM Power处理器的硬件平台上提供了具有行业领先水平的虚拟化技术家族——PowerVM。
PowerVM是一套完整强大的虚拟化。为了让每个处理器都能做到物尽其用,PowerVM的“微分区技术”允许对工作负载进行管理,将微分区的大小定义为一个处理器的 1/10,并以小到一个处理器的 1/100 的增量更改它。可以为每个核心创建最多 10 个微分区。通过PowerVM技术,客户还可以获得服务器上的各种I/O资源,比如分配给一个分区的物理适配器可以由一个或多个其他分区共享,使管理员可将用于各个客户机的物理适配器的数量降到最低。最方便的是,它具有一个虚拟化管理器(IVM),管理员可以通过浏览器,直观地管理这台庞大的虚拟电脑。
当然,对于系统管理员来说,通过虚拟化技术来管理一个看不见摸不着的“云”,需要的不仅是功能如何强大,更重要的是丰富的配置策略和完善的管理预案。2012年,IBM推出了基于Puresystem 服务器的Flex System Manager(FSM)“专家集成系统”,让虚拟化管理更加人性化。FSM是虚拟化软件与硬件的结合,外形上和一台服务器差不多,不过它可不是一台普通的服务器,而是一个集成了IBM 40余年来在基础架构与虚拟化方面的经验的虚拟顾问团,它预设了200多种规则与智能化的触发脚本,可以对整个“云”进行主动管理。如果你是这台“巨型电脑”的操作者,那就暗自庆幸吧,这才是真正的优化大师。
【平等,无论真实还是虚拟】
在云时代,虚拟化技术让云端各种规格的服务器、存储装置、网络设备,在管理员眼中成为平等的存在,让他们可以像操作一台电脑一样,管理远在千里之外的现实中的设备。而如今的 “云”具备了更加智慧的能力,通过虚拟化技术构建的各种各样的云服务,也让使用它的人们更加平等,不管你是何身份,只要有一台PC、手机或平板,都平等的享受着云端提供的各种信息和服务。这是虚拟化带来的平等机会,拉近了你我之间的距离。
实例开发架构:android调用wcf service服务(注意是service服务,不是restful风格,后面再讲restful风格的调用)。
动手之前,先一个ksoap2-android,它是我们调用wcf服务的工具。在官网上下载过好几次都不能用,后来发现原来下载的不是完整的。所以大家可以到这下载http://download.csdn.net/detail/leesmn/5162649。
wcf部分(使用的是VS2012):
1、新建wcf类库odbServiceLib。定义IService,以及定义数据约定
namespace odbServiceLib
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
[ServiceContract]
public interface IService
{
[OperationContract]
int PostDaignoseJson(string jsonStr);
[OperationContract]
string PostConsultJson(string jsonStr);
[OperationContract]
Consult GetConsult(string imei);
// TODO: 在此添加您的服务操作
}
// 使用下面示例中说明的数据约定将复合类型添加到服务操作。
// 可以将 XSD 文件添加到项目中。在生成项目后,可以通过命名空间“odbServiceLib.ContractType”直接使用其中定义的数据类型。
[DataContract]
public class Diagnose
{
[DataMember]
public string imei { get; set; }
[DataMember]
public double longitude { get; set; }
[DataMember]
public double latitude { get; set; }
[DataMember]
public string datetime { get; set; }
[DataMember]
public int type { get; set; }
[DataMember]
public string content { get; set; }
}
[DataContract]
public class Consult
{
[DataMember]
public string imei { get; set; }
[DataMember]
public double longitude { get; set; }
[DataMember]
public double latitude { get; set; }
[DataMember]
public string datetime { get; set; }
[DataMember]
public int type { get; set; }
[DataMember]
public string text { get; set; }
[DataMember]
public string imgstr { get; set; }
[DataMember]
public byte[] img1 { get; set; }
}
}
2、实现Service。在该段代码中本人用了vs自带的ado.net entity framwork作为orm操作数据库
namespace odbServiceLib
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service1”。
public class Service : IService
{
public int PostDaignoseJson(string jsonStr)
{
Diagnose d;
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonStr)))
{
DataContractJsonSerializer serializer1 = new DataContractJsonSerializer(typeof(Diagnose));
d = (Diagnose)serializer1.ReadObject(ms);
}
//System.Data.Common.DbTransaction tran = null;
int i = 0;
try
{
using (carobdEntities ctx = new carobdEntities())
{
ctx.Database.Connection.Open();
//tran = ctx.Database.Connection.BeginTransaction();
StringBuilder strb = new StringBuilder();
strb.Append("create table if not EXISTS diag");
strb.Append(d.imei);
strb.Append("(id int not null auto_increment,");
strb.Append("longitude double,");
strb.Append("latitude double,");
strb.Append("datetime datetime,");
strb.Append("type int,");
strb.Append("content varchar(500),");
strb.Append("PRIMARY KEY (id) )");
if (ctx.Database.ExecuteSqlCommand(strb.ToString()) > 0)
ctx.SaveChanges();
strb.Clear();
strb.Append("insert into diag");
strb.Append(d.imei);
strb.Append("(longitude,latitude,datetime,type,content)values(");
strb.Append(d.longitude);
strb.Append(",");
strb.Append(d.latitude);
strb.Append(",'");
strb.Append(d.datetime);
strb.Append("',");
strb.Append(d.type);
strb.Append(",'");
strb.Append(d.content);
strb.Append("')");
if (ctx.Database.ExecuteSqlCommand(strb.ToString()) > 0)
i = ctx.SaveChanges();
//tran.Commit();
}
}
catch { i = -1; }
return i;
}
public string PostConsultJson(string jsonStr)
{
Consult c;
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonStr)))
{
DataContractJsonSerializer serializer1 = new DataContractJsonSerializer(typeof(Consult));
c = (Consult)serializer1.ReadObject(ms);
}
c.img1 = Convert.FromBase64String(c.imgstr);
//System.Data.Common.DbTransaction tran = null;
int i = 0;
try
{
using (carobdEntities ctx = new carobdEntities())
{
ctx.Database.Connection.Open();
//tran = ctx.Database.Connection.BeginTransaction();
StringBuilder strb = new StringBuilder();
strb.Append("create table if not EXISTS cons");
strb.Append(c.imei);
strb.Append("(id int not null auto_increment,");
strb.Append("longitude double,");
strb.Append("latitude double,");
strb.Append("datetime datetime,");
strb.Append("type int,");
strb.Append("text varchar(500),");
strb.Append("img1 longblob,");
strb.Append("PRIMARY KEY (id) )");
if (ctx.Database.ExecuteSqlCommand(strb.ToString()) > 0)
ctx.SaveChanges();
strb.Clear();
strb.Append("insert into cons");
strb.Append(c.imei);
strb.Append("(longitude,latitude,datetime,type,text,img1)values(");
strb.Append(c.longitude);
strb.Append(",");
strb.Append(c.latitude);
strb.Append(",'");
strb.Append(c.datetime);
strb.Append("',");
strb.Append(c.type);
strb.Append(",'");
strb.Append(c.text);
strb.Append("',");
strb.Append("{0}");
strb.Append(")");
if (ctx.Database.ExecuteSqlCommand(strb.ToString(), c.img1) > 0)
i = ctx.SaveChanges();
//tran.Commit();
}
}
catch (Exception e) { i = -1; return e.Message; }
return i.ToString();
}
public Consult GetConsult(string imei)
{
Consult c = null;
try
{
using (carobdEntities ctx = new carobdEntities())
{
ctx.Database.Connection.Open();
//tran = ctx.Database.Connection.BeginTransaction();
StringBuilder strb = new StringBuilder();
strb.Append("select * from cons");
strb.Append(imei);
strb.Append(" order by id DESC limit 1");
c = ctx.Database.SqlQuery<Consult>(strb.ToString()).FirstOrDefault();
//tran.Commit();
}
}
catch (Exception e) { }
return c;
}
}
}
3、新建web-〉wcf服务。将默认生成的IService以及Service删除掉。将odbServiceLib 类库添加到本项目中。编辑Service.svc的标记
<%@ ServiceHost Language="C#" Debug="true" Service="odbServiceLib.Service" %>
到此wcf端就大功告成了运行一下看看能不能打开Service.svc
android部分:
1、确保已经将ksoap2-android加载到项目中
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://192.168.1.108:8082/Service.svc";
private static String METHOD_NAME = "";
private static String SOAP_ACTION = "";
public static String call(String methodName, String jsonStr) {
String restr = "";
METHOD_NAME = methodName;
SOAP_ACTION = "http://tempuri.org/IService/" + methodName;
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("jsonStr", jsonStr);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive result = (SoapPrimitive) envelope.getResponse();
// to get the data
restr = result.toString();
// 0 is the first object of data
// sb.append(resultData + "\n");
} catch (Exception e) {
restr = "Error:" + e.getMessage();
}
return restr;
}
private void PostDaignoseJson()
{
JSONObject object = new JSONObject();
try {
object.put("imei", phoneIMEI);
object.put("longitude", x);
object.put("latitude", y);
object.put("datetime", sdf.format(new Date()));
object.put("type", type);
object.put("content", diagData);
} catch (JSONException e) {
e.printStackTrace();
}
call("PostDaignoseJson", object.toString());
}
private void PostConsultJson(){
imgStr = new String(Base64.encode(imgBuf));
JSONObject object = new JSONObject();
try {
object.put("imei", phoneIMEI);
object.put("longitude", x);
object.put("latitude", y);
object.put("datetime", sdf.format(new Date()));
object.put("type", 1);
object.put("text", consData);
object.put("imgbase64", imgStr);
} catch (JSONException e) {
e.printStackTrace();
}
call("PostConsultJson", object.toString());
}
说明:对于上传图片的问题有点麻烦,不能之间将byte[]转为json,所以先将他Base64.encode编码为String.