2011年10月1日,MagicJelly Game Studio成立。
        2011年11月21日,Game Kingdom Studio成立。
        2011年12月14日, "CastleDefense"由Game Kingdom Studio发布。
        2011年12月30日,"果冻军团"由MagicJelly Game Studio发布。

 

       截止2012年1月14日,"CastleDefense"排名MarketPlace美国市场游戏“策略模拟”分类第12位,总排名TOP119位。“果冻军团"排名MarketPlace美国市场游戏”家庭“分类第4位,总排名TOP59位,MarketPlace香港市场游戏”家庭“分类第1位,总排名Top6。
        我作为MagicJelly Game Studio和Game Kingdom Studio的创始成员之一,这两个游戏的唯一开发人员。直接操作了游戏的发布过程,掌握了这两个游戏的第一手销售资料。
        让我觉得不解的是,”果冻军团“曾经排名美国市场前50位,评分5星,收益却不如评分3.5分的”CastleDefense“。我认真思考了很久,一款游戏的收益只能由市场评判,市场才是公正的裁判。
       总结如下:
       1.目前WP7市场重点在欧美,最重要的市场是美国,所以欧美画风的CastleDefense获得欧美市场的认可要高,付费比率也要高出不少。
       2.果冻军团在香港等中文市场排名靠前,一方面做过7天的免费推广,所以下载量超过CastleDefense不少,但游戏并不为欧美市场认可。
       3.等待中国市场开放,果冻军团应该收益接近CastleDefense.
       
       对我个人而言,这2个月左右的经历收获不少,之前只所以没有对朋友们公开我要做什么,是因为我不是一个什么都没做出来就宣扬的人。
       从一个职责单纯的开发人员到一个成立游戏工作室的游戏制作人,我遇到的迷惑和困难超出我的想象,现在理清思路,我应该是走在一个正确的方向上。
       1.就目前市场容量来说,1年之内CastleDefense的成本应该可以回收,所以1年的坚持和运作很重要。
       2.WP7的市场随着Nokia的加入应该会增大而不是萎缩。
       3.国外一名独立游戏制作者去年发布了13款游戏,全部是免费的,靠广告收入6W美元,我们应该不会比他差。
       4.盈利模式很清晰,没有中间的渠道环节来增加成本,做一个好点的游戏,就能收入美元,关键是游戏的质量。
       5.中国的人力成本,特别是武汉的人力成本是外国开发者不能比的。
       我遇到的压力和困难:
      1.从一个稳定的高收入者到一个不稳定的负收入者,经济和心理压力都比较大。
      2.工作室的运作会遇到人才和资金压力,如果找到合适的人才,何时寻找或者不寻找天使投资?
      3.我们要做什么样的游戏,创新还是山寨?
      我的对策:
      1.我起起伏伏好几次了,曾经被偷成零资产,遇到比这困难的事也不少了,所以就算失败了也没什么。
      2.我会培养XNA的开发人员,同时把自己变成一个精通XNA开发的人。
      3.多和武汉的朋友交往,多接触类似于投资方,运营,培训行业的朋友。
      4.努力提升游戏质量,多关注市场。
       2012,加油吧!用CastleDefense过关画面来勉励自己:Fight!I'll win! 

 

       

最后宣传下我的工作室:Http://gamekingdom.us 

posted @ 2012-01-14 23:10 王传炜 阅读(688) 评论(3) 编辑

                                                     第 4 章XNA里的2D动画

4.1 播放游戏精灵动画

第二章里我们提到了如何把2D的纹理用SpriteBatch显示。对于游戏而言,一个精灵(sprite,在游戏编程里指一个对象的原型,比如一个战士,一个怪物)不可能不做动作,就拿简单的走动来说,手脚一定会是要动的,那么如何真实得展现一个人物在屏幕上走动呢?在2D游戏编程里,我们通常就是把人物的动作拆成一帧帧图片,通过连续播放来欺骗人眼产生动画的效果,其实胶片电影也是这个原理。

如下图4-1,是一个小兵的行走动画,可以看到是由12张图片组成,那么如何能连续循环播放呢

                                                  图4-1

一想到循环,我们就很容易想到for循环,如果我们把这12张图片的纹理放到一个Texture2D[] 数组里那么,通过for循环不就可以实现了么?

for(int i=0;i<SoldierTextures.Count;i++) //伪代码

{

spriteBatch.Draw(SoldierTextures[i]);

}

当然,这个循环只能循环一遍,如果做到从头到尾不停的循环呢?

前面我们提到XNA里的Update函数,它就是不停执行的一个函数,执行的时间间隔是一个固定值.我们就可以把这个函数当做是一个特殊的for循环.

我们需要用上一个全局的计数器FrameCount.

int FrameCount=0;

void Update() //在update函数里改变计数器

{

FrameCount++;

if(FrameCount>SoilderTextures.Length-1)//如果播完最后一帧

{

FrameCount=0; //就回到第一帧

}

}

void Draw() //在Draw函数里绘制出纹理

{

spriteBatch.Draw(SoilderTextures[FrameCount]);

}

以上代码都是伪代码,便于大家理解,实际编程中的代码比这里要复杂点。

1.在GameMainScreen类里写上构造函数:

    Texture2D[] soilderTextures;

       public GameMainScreen()

       {

           soilderTextures=new Texture2D[12];//初始化士兵纹理数组

       }

2.把12张士兵跑动图片放到Content项目下的一个Enemy文件夹的子文件夹Run中,如果4-2:

3.用for循环加载这12张图片纹理,如下:

 public override void LoadContent()

 {

     base.LoadContent();

     playerTexture = ScreenManager.Game.Content.Load<Texture2D>("Player/1");

     for (int i = 0; i < 12;i++ )

     {

 soilderTextures[i] =ScreenManager.Game.Content.Load<Texture2D>("Enemy/Run/"+(i+1));

     }

 }

4.在Draw里绘制出当前帧:

 public override void Draw(GameTime gameTime)

 {

     ScreenManager.SpriteBatch.Begin();

     ScreenManager.SpriteBatch.Draw(soilderTextures[FrameCount],new Vector2(100,200), Color.White);

     ScreenManager.SpriteBatch.End();

  }

 

        图4-2

5.在Update里更新当前帧的位置,依次向后播放:

 public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)

  {

      base.Update(gameTime, otherScreenHasFocus,coveredByOtherScreen);

      float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

      FrameCount++;

      if(FrameCount > soilderTextures.Length - 1)//如果播完最后一帧

      {

           FrameCount = 0; //就回到第一帧

      }

  }

6.在模拟器最后运行效果如图4-3:

我们执行上面写好的代码后,就在模拟器里发现人物就循环播放动画了,不过出现了新问题:士兵的跑动动作频率不够合理,像一个超人一样飞速得在奔跑。

这是为什么呢?

因为人物动画帧播放的时间间隔其实是要远大于update函数执行的时间间隔的,比如说人物动画是1秒播放一帧,而update函数是1/30秒(0.3333秒)播放一帧。那么我们如何处理这个问题呢?

在回到上面的代码里,其实只要控制 FrameCount++执行的时间间隔就可以了。如何控制?那么我们需要用到另外一个计数器updateCount;

updateCount++;

if(updateCount>TimeSpan) //伪代码,TimeSpan为时间间隔量

{

FrameCount++;

updateCount=0;

}

这样我们通过修改TimeSpan的值就能控制FrameCount++执行的时间间隔了。比如TimeSpan=30, 那么update函数要执行30次,FrameCount++才执行一次。也就说FrameCount++执行的时间间隔为 30*0.33333秒=1秒。

经过合理调整,我们发现TimeSpan=2时,士兵的动作频率最协调,代码如下:

      int updateCount=0,timeSpan=2;

       public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)

       {

           base.Update(gameTime,otherScreenHasFocus, coveredByOtherScreen);

           float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

           updateCount++;

           if(updateCount > timeSpan) // timeSpan为时间间隔量

           {

              FrameCount++;

              updateCount = 0;

           }

           if(FrameCount > soilderTextures.Length - 1)//如果播完最后一帧

           {

               FrameCount = 0; //就回到第一帧

           }

       }

写完以上代码,我们就能看到精灵动画能够自如的播放了。不过这个小兵精灵并不能移动,所以有些别扭。那么我们下面一节就要研究如何让精灵移动起来。

4.2游戏精灵的矢量移动

我们在前面第二章讲过可以指定得把一个2D纹理绘制在特定的坐标位置上。在WP7的XNA里,坐标系如下,原点的位置是左上角,X轴向右延伸,Y轴向下延伸。

在XNA里,2维坐标用Vector2对象来表示:

Vector2 position = new Vector2(X,Y);

了解了XNA里2维坐标概念后,我们还需要知道一个概念就是运动矢量,什么叫运动矢量呢?比如我向右走,也就是笔直沿X轴增大的方向走,这样我行走的方向就确定了,但是我行走的时候可快可慢,这就涉及到速度的问题。运动矢量就包含了方向和速度两个概念。在2维坐标系里,运动矢量也用Vector2 对象来表示。我用20单位的速度向右走就可以表示为 new Vector2(20,0); 很容易理解此时在X轴方向上以20单位的速度在增大(向右运动),在Y轴上没有变化。

那么随着时间流逝,我们就能得到运动中的精灵在当前时刻所在坐标位置,用矢量计算公式:

Vector2 speed = new Vector2(20,0);

Vector2 EndPosition = position + speed*elipsetime;

计算出EndPosition后,我们就在Draw方法里

spriteBatch.Draw(Texture2D,EndPosition);

这样我们的精灵就能移动了,改变speed运动矢量,我们就能控制精灵的运动速度和方向。当然,要让精灵停下来也很简单,speed = new Vector2(0,0)就可以了。

改进后的代码如下:

       int FrameCount= 0;

       Vector2 endPosition = new Vector2(0,200);

       public override void Draw(GameTime gameTime)

       {

           float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

           float totalTime = (float)gameTime.TotalGameTime.TotalSeconds;

           ScreenManager.SpriteBatch.Begin();

           ScreenManager.SpriteBatch.Draw(soilderTextures[FrameCount], endPosition,Color.White);

           ScreenManager.SpriteBatch.End();

       }

         int updateCount=0,timeSpan=2;

       Vector2 speed=new Vector2(100,0);

       public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)

       {

           base.Update(gameTime,otherScreenHasFocus, coveredByOtherScreen);

           float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

           updateCount++;

           if(updateCount > timeSpan) //TimeSpan为时间间隔量

           {

               FrameCount++;

               updateCount = 0;

           }

           if(FrameCount > soilderTextures.Length - 1)//如果播完最后一帧

           {

               FrameCount = 0; //就回到第一帧

           }

           endPosition += elapsedTime * speed;

           if(endPosition.X>800)

           {

               endPosition = new Vector2(0,200);

           }

       }

 按F5运行模拟器后,我们会看到一个不停奔跑的士兵。

4.3制作可控的游戏精灵

      在手机游戏里,主角一般都是方向可控的,如下图4-4是一个带十字方向键的iphone游戏界面:


                                                   图4-4                       
                            
 

       结合我们第3章讲的WP7的触控操作,我们也能实现十字方向键控制的游戏精灵。

1.     首先找到一个十字键图片,把它绘制到手机左下角,如图4-5:


 

              图4-5


 

2.     设定4个方向点的矩形范围。

        Rectangle topRect = newRectangle

       {

           Location = newPoint { X = 40, Y = 380 },

           Width = 30,

           Height = 30,

       };

       Rectangle bottomRect = new Rectangle

       {

           Location = new Point { X = 40, Y = 460 },

           Width = 30,

           Height = 30,

       };

       Rectangle leftRect = new Rectangle

      {

           Location = new Point { X = 2, Y = 410 },

           Width = 30,

          Height = 30,

      };

      Rectangle rightRect = new Rectangle

      {

           Location = new Point { X = 80, Y = 410 },

           Width = 30,

           Height = 30,

       };

 

2.     重写HandleInput函数,接受触控操作:

       public override void HandleInput(InputHelperinput)

       {

         TouchCollection touchState = TouchPanel.GetState();

           foreach(TouchLocation tl in touchState)

           {        

              if(topRect.Contains(new Point{ X = (int)tl.Position.X, Y = (int)tl.Position.Y }) && tl.State == TouchLocationState.Pressed)

               {

                   speed = new Vector2(0,-100);

               }

             if(bottomRect.Contains(new Point { X = (int)tl.Position.X,Y = (int)tl.Position.Y }) &&tl.State==TouchLocationState.Pressed)

               {

                   speed = new Vector2(0,100);

               }

               if(leftRect.Contains(new Point{ X = (int)tl.Position.X, Y = (int)tl.Position.Y }) && tl.State == TouchLocationState.Pressed)

               {

                   speed = new Vector2(-100,0);

               }

               if(rightRect.Contains(new Point { X = (int)tl.Position.X,Y = (int)tl.Position.Y }) && tl.State== TouchLocationState.Pressed)

              {

                   speed = new Vector2(100,0);

               }

               if(tl.State==TouchLocationState.Released)

               {

                  speed = new Vector2(0,0);

               }

           }

      }

3.     写好以上代码后,按F5调试,在游戏主界面,我们就看到如图4-6的效果:




                             4-6


      当然这只是个简单的DEMO,士兵后退,向上,向下的动画都不对,不过原理和士兵前进的动画一样。更复杂的动画,我们会在下一章来讲解。



   
posted @ 2011-11-27 16:21 王传炜 阅读(1136) 评论(8) 编辑
摘要: 第 3 章 创建XNA 游戏菜单 3.1 WP7里XNA游戏的触控操作 上一章节,我们了解了制作XNA 2D游戏的常用组件已及使用ScreenManage管理场景。可以说对XNA 2D游戏有了入门,不过我们玩游戏不会一开始就进入到游戏场景里的,总是会有启动界面,loading界面,然后到了游戏菜单。然后让用户选择“开始”,“继续”,“帮助”等选项,如下图3-1,就是一个常见的游戏界面。 图3-1和PC上的运行的XNA游戏不同,我们在WP7上是靠触摸屏操作的,这和用鼠标操作还是不同的。那么我们就需要先了解WP7里XNA的触控操作。现在的触摸屏手机基本都支持“多点触控”,比如拉伸,缩放,玩过Iph阅读全文
posted @ 2011-11-19 14:41 王传炜 阅读(929) 评论(3) 编辑
摘要: 第 2 章 制作XNA 2D游戏的常用组件 2.1使用LoadContent加载2D图片资源在XNA项目中,如果制作2D游戏,那么都会涉及到图片资源。比如人物的行走动画可以由连续播放一系列帧图片完成。如何在XNA里加载图片资源就是我们首先要掌握的。在上一章节,我们建了一个XNA项目解决方案,里面就带有一个Content项目。我们游戏所用的图片,音效,字体等资源都是放在这个项目里的。当然这个项目你可以认为是储存游戏资源的文件夹,方便来管理游戏资源。如何在Content项目里把不同类型的文件放置呢?跟普通站点项目一样,同类型的文件一般都放在一个文件夹里。比如图片资源都放在UI文件夹,音效文件放在S阅读全文
posted @ 2011-10-29 23:02 王传炜 阅读(746) 评论(2) 编辑

            准备写一系列XNA里设计2D游戏的文章,这是第一章。

 

                                              1.XNA里的hello world

 

1.1创建XNA游戏开发项目

      我们初学程序的时候,总是爱写一个hello world 来体验下。可以说写出hello world 是我们了解一个语言或者框架最简单的做法。那么我们如何在wp7(windows phone 7)里用xna游戏框架在屏幕输出hello world呢。

其实微软的开发工具对开发者而言是很友好的。我们打开vs2010 Express for Windows Phone,选择File->New Project菜单,新建项目XNAGameSample,如图1-1:

                              图1-1

 

     于是我们看到如下图1-2这样的解决方案:

 

                           图1-2

         对这个解决方案,在右侧的解决方案资源管理器(Solution Explorer)里我们可以看到两个项目:

XNAGameSample和XNAGameSampleContent.

        在我们项目储存的硬盘上我们可以看到图1-3这样的目录结构:

                                                 图1-3

 

     其中XNAGameSampleContent项目是我们用来管理游戏资源文件的项目,我们以后用到贴图,模型,声音等资源都会放在这里管理。

     XNAGameSample是我们的主项目。

     在XNAGameSample项目里我们开打game1.cs文件,这是游戏运行的主入口,如图1-4:

                                             图1-4

 

     在Game1.cs里面有Initialize,LoadContent,UnloadContent,Update,Draw五个方法。

那么这五个方法各自在游戏里起什么作用呢?在后面的章节里我们会了解到这五个方法各自的用途。

 

1.2 update 和draw

           从函数命名上,我们可以猜测得到LoadContent是负责加载游戏资源的。Draw 是用来绘制游戏界面的。那么Update呢,从字面意思上我们可以看到是”更新”的意思,那么这个方法里更新什么呢?

            举一个简单的游戏场景来说。如果我们绘制一个手拿盾牌的小兵,让他从手机屏幕的左边跑到右边,那么我们怎么做呢。

            首先,我们会用LoadContent来加载这个小兵所使用到的所有贴图资源。然后用Draw 方法把贴图绘制到屏幕制定的位置。但是我们要求的是小兵是移动的,从左边跑到右边,在跑的过程中还涉及到帧动画的变化。那么这些问题我们都需要在Update里来处理。简单来说,我们需要在Update里改变小兵的坐标位置和变换所用到的贴图资源。

            我们需要了解的是Update 和Draw 在游戏运行过程中是按一定时间间隔不停被调用的方法,这样我们才能看到连续的动画。用流程图我们可以这样来描述:

           

      我们在WP7上写XNA游戏的时候,需要了解一个很重要的概念,就是刷新率是多少?通俗的说,1秒钟Draw和Update 被调用多少次。

     只有弄清楚这个问题,我们才能控制2D游戏动画的播放速度。WP7xna的刷新率默认为30fps.也就是说1秒钟Draw 和Update 要被调用30次。如图1-4,我们展开Game1函数,可以看到如下代码:

           public Game1()

   {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        // Frame rate is 30 fps by default for Windows Phone.
        TargetElapsedTime = TimeSpan.FromTicks(333333);
   }

       

        其中有一段英文注释是"Frame rate is 30 fps by default for Windows Phone.",意思是Windows Phone 的默认FPS是30.

 

1.3 LoadContent 和 UnloadContent

     在1.2章节里我们已经简单介绍了LoadContent和UnloadContent的作用,如果我们需要在WP7里输出一段文字,我们就需要用到LoadContent了,在XNA里我们要经常接触到SpriteFont对象,这个对象是负责控制输出字体的,在XNA里字体的样式我们需要用一个XML文件来控制。如图1-5,我们在XNAGameSampleContent项目里创建一个新的文件夹“Fonts”,然后我们在XNAGameSampleContent项目里新建的Fonts文件夹上点击右键选择Add,然后选择New Item,再选择sprite font ,把Name改成default.spritefont,最后点击 add。

 

                                                                                       图1-5

            然后,如图1-6,我们修改default.spritefont的内容为:

 

                                                             图1-6

        做好了上面的准备工作,我们在Game1.cs里增加一个新的对象font,然后在LoadContent函数里添加如下代码:
font = Content.Load<SpriteFont>("Fonts/default");

        如图1-7:

                                                                 图1-7

 

     接着在Draw函数里写下如下代码:

         

   spriteBatch.Begin();
   spriteBatch.DrawString(font, "Hello world"new Vector2(200,100), Color.Black);
   spriteBatch.End();

 

     如图1-8:

                                                                                    图1-8

     然后我们只需要在工具条的最右边选择"Window Phone 7 Emulator"按下F5,在模拟器模式下就能运行这个小小的demo了,如图1-9:

 

                                                                                     图1-9

            那么我们怎么要在真机上调试呢?在下一章节我们就会讲到。

1.4调试和部署XNA项目

              首先,我们需要装上Zune,我们的wp7手机也需要解锁。解锁需要我们拥有WP7开发者账号。注册地址:http://create.msdn.com/。如图1-10:

              Tips:如果你有.edu的学生邮箱,又通过dreamSpark认证,就可以免去$99的年费。

                                                           图1-10

            准备好这些后,我们用数据线连上WP7真机,如果WP7被识别,会自动启动Zune。如图1-11:

                                                                                 图1-11

              然后我们在vs2010 Express for Windows Phone的工具条最右边选择"Windows Phone 7 Device"。再按F5。等几秒钟后,我们的项目编译后产生的XAP文件就被部署到真机里运行了。

     demo源代码下载地址:/Files/wangergo/XNAGameSample1.rar

 

                                                                     
posted @ 2011-10-15 19:53 王传炜 阅读(1306) 评论(4) 编辑
摘要: 游戏背景: 时间是欧洲中世纪,一位英雄坚守着他国家最后的城堡。一旦敌人攻破这个城堡,他的任务就失败了。这位英雄有着百步穿杨的本领,还有强大的魔法技能。虽然敌人发起了一波波潮水般的攻击,但他都顽强的击退了。 敌人不甘失败,派出了各种兵力,长矛兵,盾牌兵,骑兵,后来还调来投石车,空中的狮鹫骑士。敌人势要把这个城堡攻下,这位最后的英雄能守住城堡吗? 开发历程: 这个游戏我从过年开始构思,然后和美术方面的朋友沟通,本打算用XCODE写在Iphone上,后来发现自己XCODE游戏开发经验不是很足,并且App store上的游戏竞争激烈,类似的游戏也有了。于是我转到WP7平台上,用自己最拿手的C#来开发。阅读全文
posted @ 2011-08-17 11:25 王传炜 阅读(2039) 评论(27) 编辑
摘要: 今天不是圣诞节么?对我来说,是一个休息的好借口,项目组的成员都小小的身体不适过,的确比较辛苦,我这个月几乎天天迟到。一周三次更新版本让大家都神情紧张,精神不佳。我想如果办公室里有沙袋的话,我会天天胖揍它一顿。其实这个主意不错,买一个沙袋和拳击手套放到公司里,让大家不爽的时候出出气啥的。 好多同学也许要问,老师,你现在在做什么项目啊。说来话长,就从年初开始讲起吧。1月份的时候,我到北京面试成功,职位是web game开发小组的 Team leader.薪水达到了我的预期。我决定离职,离开工作了3年多的北大青鸟。为了离职我准备了近一年的时候,一方面我对技术进行了储备,学了asp.net MVC,阅读全文
posted @ 2010-12-25 17:25 王传炜 阅读(2493) 评论(25) 编辑
摘要: 在我开始写Web传奇的时候,就在想一个问题:如果我把所有的地图,怪物图片,音效等游戏资源都放在XAP包里,这个XAP包就会越来越大。在我很早以前玩传奇2的时候,安装包就300多M,后来传奇3就有1G多了。如果等我的web传奇越写越大的时候,那我的游戏需要loading多久啊,玩家可等不了。所以我把微软的文档找来,发现有独立储存区域这个东西,微软的解释如下:[代码] 于是我就有这样的设想: 1.把...阅读全文
posted @ 2010-05-26 22:52 王传炜 阅读(2302) 评论(16) 编辑
摘要: 上回说到Server少爷和Client小姐好不容易踏入婚姻的殿堂,洞房花烛之夜,Client小姐却要Server少爷签下婚后协议。Server一脸不快:“都一家人还签什么协议啊?”Client道:“你们男人啊,就是花心,不看紧点,不知道跑那野去了。为了以后我们能琴瑟相合,还是签了协议的好。”Server呵呵一笑:“好老婆,那就签吧,你开心...阅读全文
posted @ 2010-05-09 01:14 王传炜 阅读(3283) 评论(33) 编辑
摘要: 新郎Server的房子装修好了,就看这边Client 的嫁妆准备如何了。Client小姐出身Silverlight名门,天生高傲较贵,只让给她服务的仆人使用TCP协议,UDP都不能考虑。 至于Client家的仆人做事,那是大家风范,全部使用"异步"方式。你看看他们的名字:一个是ConnectAsync,一个是SendAsync,还有一个是ReceiveAsync。另外还有两个打杂,负责关门看院的...阅读全文
posted @ 2010-05-03 13:25 王传炜 阅读(2246) 评论(14) 编辑