存档

2009年7月 的存档

What are the “gotchas” when developing an iPhone Game?

2009年7月24日 没有评论

Am used to developing business and reference apps. Now I have to do an iPhone game. What tips can you share to help me with:

  1. understanding the scope of the project
  2. defining the deliverables
  3. specifying the game play and other parameters
  4. estimating the development effort
  5. testing the game

A big question, I know. Thanks!

The main difference between business apps and games, especially on mobile devices, is the importance of performance. An app that puts up a form and waits for user input probably isn’t doing anything in the meantime. A game loop, on the other hand is going all the time and probably doing alot. Business programmers are not used to thinking in these terms, but games draw down battery power and, believe it or not, how you implement your game will have a great effect on how quickly that battery is drawn down.

So, one question is, what is this game that you “have to” develop? If it is sudoku, no worries. If it’s a real-time 3D space battle, that’s another story.

If your business apps were on the iPhone, then you probably used 100% Objective-C. (If you were doing C# or Java apps on desktops, then welcome to managing your own memory.) There are those who will tell you that the runtime type management of Objective-C is too slow for complex games. People certainly make OK games using it with Cocos2D and other engines, but again it depends on the game. There are professional developers who will only work with C++ or even straight C.

My answer is not following the waterfall methodology response you were looking for because I think you will need to learn the skill of game programming before you can plan, design, implement and test it. Game programming is VERY different to business programming and a whole other field in and of itself.

Due to your lack of experience in programming games there are a few concepts that you will need to learn before you can program a game period, let alone one on the iPhone.

Some of these things will depend on whether you are programming a 3D game or going for the 2D platform style.

OpenGL ES
The first thing you will need to learn is the OpenGL ES programming language. This is basically a 3D API which enables you to do drawing of 3D primitives. You will still need to use this if you are coding a 2D game as it is quick due to using the GPU for acceleration.
There are some good tutorials on the Google that you should begin with.

Vector Math
If you are doing anything 3D, you will need to learn about 3D vector math, vectors are basically used for everything in games, camera look direction, position of characters, speed, collision detection, etc. 2D vectors (x,y) minus the z component are still needed for 2D games programming.

Collision Detection
How do I know when my ball hits the wall? The answer is collision detection. There are many forms of collision detection such as Sphere to Sphere, AABB, OOBB, Convex Hulls, Triangle Mesh, etc.

AI
How do I get the enemy to attack my player character? Artificial intelligence is another large field essential to give NPCs/Enemies the ability to make intelligent decisions. AI can be simple such as if else statements but usually requires Finite State Machines or Fuzzy logic to be effective.

Pathfinding
If you want to move a character from Point A to Point B while avoiding enemies and moving obstacles, you will need to use a pathfinding algorithm. A Star (A*) is one of the most popular.

Scene Graph
If you wish to have 10-20+ enemies on screen at a time, you will need to code a scene graph to manage the dynamic drawing, logic and creation and deletion of resources. If you don’t know what polymorphism is you will need to know it as it is essential for your game objects to adhere to and it ties in with the scene graph.

Physics
Position, Speed, Acceleration, Gravity and Rays are all represented using vectors and you may need to brush up on your physics math in order to code any game. Start with Newton’s Second law of motion F=MA (Force = Mass * Acceleration). An open source physics engine such as Bullet, ODE, Newton, Tokamak will make things easier, meaning you won’t need to write these physics rules yourself.

Objective-C++
This is optional although recommended. If you don’t know C++ this is essentially a mixture of C++ and Objective-C. I tend to use C++ for the core game engine and programming because of the speed of C++ and availability of third party libraries in C++.

Sound
If you need sound you can just go ahead and use the simple audio frameworks that Apple provide, however 3D positional audio is going to require something better. I would recommend learning the FMOD SDK for iPhone. As @Stowelly mentioned, FMOD requires a license for commercial distribution but there are others you can look for which are royalty free.


Use a Game Engine
There are game engines available for the iPhone at the moment which will make it much easier for you to get a game going, in your case this will be faster although you will still need to learn the concepts I mentioned above.

Here are some game engines I know of:

Unity3D
This probably the most popular one that I know of. Unity is a PC/Mac game engine that lets you write code on the Mac and compile for Windows/Linux/Mac OS X. I doubt the iPhone building is compatible directly with other platforms, I would imagine you’d be restricted to iPhone if you started a new project. This engine does however have a commercial deployment cost of $199-$399.

Cocos2D
This one is an open source 2D game engine that might be useful for a lot of games. Worth taking a look at. Hosted on Google code.

Here are some others to check out:

Ston3D for iPhone

OOlong Engine

SIO2Engine

iTGB for 2D Games

分类: cocos2d, stackoverflow精选 标签:

以前做的一个3D地球

2009年7月12日 没有评论

以前做的一个3D地球

 

         今天请同学们来家里,初次来做客,一个同学说要下个Google Earth查查大家的位置。晚上清理U盘时在以前的一些小作品例子中查到了这个东东。呵呵。是06年做的。模仿GOOGLE EARTH做的。可以进行视角转换,显示经纬线。显示城市。可以查找对应的经纬度。

分类: 未分类 标签:

利用OGRE的海洋例子改成的水编辑器

2009年7月10日 没有评论

           看了海洋的例子之后,我们知道其实水的效果关键就在于材质中各个属性的调节。所以我就以例子中的材质制做了一个可以加载和保存的水编辑器。

           另外通过修改HLSL文件和material文件加上了透明度调节。

 

利用OGRE的海洋例子改成的水编辑器

 

要修改的部分为:

PS声明:

 

fragment_program HLSL/Ocean2FS hlsl
{
 source Ocean2HLSL_Cg.frag
 entry_point main
 target ps_2_0
 default_params
 {
  param_named vertexcolor float4 1.0 1.0 1.0 1.0
 }
}

材质中的定义

 

   fragment_program_ref HLSL/Ocean2FS
   {
    param_named deepColor float4 0 0.3 0.5 1.0
    param_named shallowColor float4 0 1 1 1.0
    param_named reflectionColor float4 0.95 1 1 1.0
    param_named reflectionAmount float 1.0
    param_named reflectionBlur float 0.0
    param_named waterAmount float 0.3
    param_named fresnelPower float 5.0
    param_named fresnelBias float 0.328
    param_named hdrMultiplier float 0.471
    param_named_auto vertexcolor  custom 1
   }

 

 

Ocean2HLSL_Cg.frag

 

/*********************************************************************NVMH3****
Copyright NVIDIA Corporation 2003
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS
BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS)
ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Comments:
 Simple ocean shader with animated bump map and geometric waves
 Based partly on “Effective Water Simulation From Physical Models”, GPU Gems

11 Aug 05: heavily modified by Jeff Doyle (nfz) for Ogre

******************************************************************************/

 

struct v2f {
 float4 Position  : POSITION;  // in clip space
 float3 rotMatrix1 : TEXCOORD0; // first row of the 3×3 transform from tangent to obj space
 float3 rotMatrix2 : TEXCOORD1; // second row of the 3×3 transform from tangent to obj space
 float3 rotMatrix3 : TEXCOORD2; // third row of the 3×3 transform from tangent to obj space

 float2 bumpCoord0 : TEXCOORD3;
 float2 bumpCoord1 : TEXCOORD4;
 float2 bumpCoord2 : TEXCOORD5;

 float3 eyeVector  : TEXCOORD6;
};

float4 main(v2f IN,
   uniform sampler2D NormalMap,
   uniform samplerCUBE EnvironmentMap,
   uniform float4 deepColor,
   uniform float4 shallowColor,
   uniform float4 reflectionColor,
   uniform float reflectionAmount,
   uniform float reflectionBlur,
   uniform float waterAmount,
   uniform float fresnelPower,
   uniform float fresnelBias,
   uniform float hdrMultiplier,
   uniform float4 vertexcolor
   ) : COLOR
{
 // sum normal maps
 // sample from 3 different points so no texture repetition is noticeable
    float4 t0 = tex2D(NormalMap, IN.bumpCoord0) * 2.0 – 1.0;
    float4 t1 = tex2D(NormalMap, IN.bumpCoord1) * 2.0 – 1.0;
    float4 t2 = tex2D(NormalMap, IN.bumpCoord2) * 2.0 – 1.0;
    float3 N = t0.xyz + t1.xyz + t2.xyz;

    float3x3 m; // tangent to world matrix
    m[0] = IN.rotMatrix1;
    m[1] = IN.rotMatrix2;
    m[2] = IN.rotMatrix3;

    N = normalize( mul( N, m ) );

 // reflection
    float3 E = normalize(IN.eyeVector);
    float4 R;
    R.xyz = reflect(E, N);
    // Ogre conversion for cube map lookup
    R.z = -R.z;
    R.w = reflectionBlur;
    float4 reflection = texCUBEbias(EnvironmentMap, R);
    // cheap hdr effect
    reflection.rgb *= (reflection.r + reflection.g + reflection.b) * hdrMultiplier;

 // fresnel
    float facing = 1.0 – max(dot(-E, N), 0);
    float fresnel = saturate(fresnelBias + pow(facing, fresnelPower));

    float4 waterColor = lerp(shallowColor, deepColor, facing) * waterAmount;

    reflection = lerp(waterColor,  reflection * reflectionColor, fresnel) * reflectionAmount;
    return (waterColor + reflection)*vertexcolor;
}

分类: 未分类 标签:

OGRE例子:Demo_Ocean 源码解析

2009年7月7日 没有评论

             因为最近在做水,所以这篇海洋的例子是必须要读懂的。

             耐着性子看了一下,还是能看懂的。现在将代码解析放上来。

程序共有四个文件:

MaterialControls.h    :

MaterialControls.cpp

包含一个Shader属性结构和材质结构。其中Shader属性结构对应于海洋中模型对应VS,PS的一些属性。

材质结构中包含了若干这个属性。使用一个容器来存放。

另外有两个函数讲述了如何从资源名称中得到scripts目录下的Ocean.controls文件,并从中将一大堆的的材质和Shader属性信息载入到对应的结构中。

 

 

OceanDemo.h

OceanDemo.cpp

 

程序和界面框架。

 

//============================================================

OceanDemo.h

/*
—————————————————————————–
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.

材质控制器,对材质的各种参数进行设置
—————————————————————————–
*/

#ifndef __MaterialControls_H__
#define __MaterialControls_H__

#include “CEGUI/CEGUIForwardRefs.h”
#include “OgreString.h”

//Shader参数类型
enum ShaderValType
{
 GPU_VERTEX, GPU_FRAGMENT, MAT_SPECULAR, MAT_DIFFUSE, MAT_AMBIENT, MAT_SHININESS, MAT_EMISSIVE
};
//顶点
//碎片
//反射
//漫反射
//环境光
//镜面反射
//发射光
//—————————————————————————

//Shader控制器(一个Shader属性的结构)
struct ShaderControl
{
    Ogre::String Name;     //Shader名称
 Ogre::String ParamName;    //属性名称
 ShaderValType ValType;    //Shader参数类型
 float MinVal;      //最小值
 float MaxVal;      //最大值
 size_t ElementIndex;    //属性索引
 mutable size_t PhysicalIndex;  //物理索引

 float getRange(void) const { return MaxVal – MinVal; }   //取得差值
 float convertParamToScrollPosition(const float val) const { return val – MinVal; } //由属性取得对应滚动条的索引位置
 float convertScrollPositionToParam(const float val) const { return val + MinVal; } //由索引取得对应的属性
};

//Shader属性结构容器
typedef std::vector<ShaderControl> ShaderControlsContainer;
//对应的迭代器
typedef ShaderControlsContainer::iterator ShaderControlIterator;
// used for materials that have user controls

//—————————————————————————
//材质控制器
class MaterialControls
{
public:
    MaterialControls(const Ogre::String& displayName, const Ogre::String& materialName)
        : mDisplayName(displayName)
        , mMaterialName(materialName)
    {
    };

    ~MaterialControls(void){}
 //取得显示名称
    const Ogre::String& getDisplayName(void) const { return mDisplayName; }
 //取得材质名称
    const Ogre::String& getMaterialName(void) const { return mMaterialName; }
 //取得Shader属性的数量
    size_t getShaderControlCount(void) const { return mShaderControlsContainer.size(); }
 //取得对应的Shader控制结构
    const ShaderControl& getShaderControl(const size_t idx) const
    {
        assert( idx < mShaderControlsContainer.size() );
        return mShaderControlsContainer[idx];
    }
    /** add a new control by passing a string parameter

    @param
      params is a string using the following format:
        “<Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>”

        <Control Name> is the string displayed for the control name on screen
        <Shader parameter name> is the name of the variable in the shader
        <Parameter Type> can be GPU_VERTEX, GPU_FRAGMENT
        <Min Val> minimum value that parameter can be
        <Max Val> maximum value that parameter can be
        <Parameter Sub Index> index into the the float array of the parameter.  All GPU parameters are assumed to be float[4].

    */
 //增加一个Shader属性结构
    void addControl(const Ogre::String& params);

protected:

    Ogre::String mDisplayName;   //显示名称
    Ogre::String mMaterialName;   //材质名称
          //Shader属性容器
    ShaderControlsContainer mShaderControlsContainer;
};

//多个材质的容器
typedef std::vector<MaterialControls> MaterialControlsContainer;
//对应的迭代器
typedef MaterialControlsContainer::iterator MaterialControlsIterator;

//—————————————————————————
//CEGUI的界面结构
struct ShaderControlGUIWidget
{
 CEGUI::Window*  TextWidget;     //标题
 CEGUI::Window*  NumberWidget;    //窗体数量
 CEGUI::Scrollbar*   ScrollWidget;    //滚动条

 ShaderControlGUIWidget() : TextWidget(NULL), NumberWidget(NULL), ScrollWidget(NULL) {}
};

//—————————————————————————
/** loads material shader controls from a configuration file
    A .controls file is made up of the following:

    [<material display name>]
    material = <material name>
    control = <Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>

    <material display name> is what is displayed in the material combo box.
    <material name> is the name of the material in the material script.
    control is the shader control associated with the material. The order
    of the contol definions in the .controls file determins their order
    when displayed in the controls window.

    you can have multiple .controls files or put them all in one.
*/
//从文件中载入材质
void loadMaterialControlsFile(MaterialControlsContainer& controlsContainer, const Ogre::String& filename);
/** load all control files found in resource paths
*/
//载入所有的材质
void loadAllMaterialControlFiles(MaterialControlsContainer& controlsContainer);

#endif // __MaterialControls_H__

 

//======================================================

MaterialControls.cpp:

 

/*
—————————————————————————–
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
—————————————————————————–
*/

#include “MaterialControls.h”
#include “OgreLogManager.h”
#include “OgreStringVector.h”
#include “OgreStringConverter.h”
#include “OgreConfigFile.h”
#include “OgreResourceGroupManager.h”
#include “OgreException.h”

/********************************************************************************
            MaterialControls Methods 材质容器的各种方法
*********************************************************************************/
//增加一个控制器
void MaterialControls::addControl(const Ogre::String& params)
{
    // params is a string containing using the following format:
    //  “<Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>”

    // break up long string into components
 // 由字符串’,’进行分隔得出属性名称装在字符串容器中
    Ogre::StringVector vecparams = Ogre::StringUtil::split(params, “,”);

    // if there are not five elements then log error and move on
 // 如果容器大小不对则出错
    if (vecparams.size() != 6)
    {
        Ogre::LogManager::getSingleton().logMessage(
            “Incorrect number of parameters passed in params string for MaterialControls::addControl()” );

        return;
    }
 //一个新的Shader属性
    ShaderControl newControl;
 //字符串容器中第一个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[0]);
 //设置为对应的名称
    newControl.Name = vecparams[0];
 //字符串容器中第二个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[1]);
 //设置为对应的属性名称
    newControl.ParamName = vecparams[1];
 //字符串容器中第三个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[2]);
 //判断对应的属性类型是VS还是PS
    if (vecparams[2] == “GPU_VERTEX”)
        newControl.ValType = GPU_VERTEX;
    else if (vecparams[2] == “GPU_FRAGMENT”)
        newControl.ValType = GPU_FRAGMENT;
 //该属性对应的最小值和最大值
    newControl.MinVal = Ogre::StringConverter::parseReal(vecparams[3]);
    newControl.MaxVal = Ogre::StringConverter::parseReal(vecparams[4]);
 //属性索引
    newControl.ElementIndex = Ogre::StringConverter::parseInt(vecparams[5]);
 //放入属性容器中
    mShaderControlsContainer.push_back(newControl);

}

//载入材质
void loadMaterialControlsFile(MaterialControlsContainer& controlsContainer, const Ogre::String& filename)
{
    // Load material controls from config file
 // 一个CFG文件
    Ogre::ConfigFile cf;

    try
    {
  //载入文件

        cf.load(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, “/t;=”, true);

        // Go through all sections & controls in the file
  //取得CFG文件读入后信息容器的对应的迭代器
        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
  //键名,种类名,材质名,数据段
        Ogre::String secName, typeName, materialName, dataString;
  //轮循取出CFG文件信息
        while (seci.hasMoreElements())
        {
   //键名
            secName = seci.peekNextKey();
   //以MultiMap方式取得对应信息容器
            Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
            if (!secName.empty() && settings)
            {
    //取得材质名称
                materialName = cf.getSetting(“material”, secName);
    //一个新的材质控制器
                MaterialControls newMaaterialControls(secName, materialName);
    //放入材质容器
                controlsContainer.push_back(newMaaterialControls);
    //取得放入容器后对应的索引
                size_t idx = controlsContainer.size() – 1;
    //对应的迭代器
                Ogre::ConfigFile::SettingsMultiMap::iterator i;
    //将属性加入其对应的Shader属性容器
                for (i = settings->begin(); i != settings->end(); ++i)
                {
                    typeName = i->first;
                    dataString = i->second;
                    if (typeName == “control”)
                        controlsContainer[idx].addControl(dataString);
                }
            }
        }
  //输入“安装完成”
     Ogre::LogManager::getSingleton().logMessage( “Material Controls setup” );
    }
    catch (Ogre::Exception e)
    {
        // Guess the file didn’t exist
  // 如果有异常
    }
}

//载入所有材质文件
void loadAllMaterialControlFiles(MaterialControlsContainer& controlsContainer)
{
 //取得对应的controls文件名,生成一个字符串容器
    Ogre::StringVectorPtr fileStringVector = Ogre::ResourceGroupManager::getSingleton().findResourceNames( Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, “*.controls” );
    std::vector<Ogre::String>::iterator controlsFileNameIterator = fileStringVector->begin();
 //遍历字符串容器,由字符串载入对应的材质文件
    while ( controlsFileNameIterator != fileStringVector->end() )
 {
  //载入对应材质
        loadMaterialControlsFile(controlsContainer, *controlsFileNameIterator);
  //迭代器++
        ++controlsFileNameIterator;
 }
}

对于框架文件,只需要知道:

/————————————————————————–
//将界面上的数据反映到Shader控制器上
bool OceanDemo::handleShaderControl(const CEGUI::EventArgs& e)
{
 using namespace CEGUI;
 using namespace Ogre;

 //由索引取得是哪个材质的哪个Shader控制器
 size_t index = ((Scrollbar*)((const WindowEventArgs&)e).window)->getID();
    const ShaderControl& ActiveShaderDef = mMaterialControlsContainer[mCurrentMaterial].getShaderControl(index);
 
 //由滚动条的值取得对应的属性
 float val = ((Scrollbar*)((const WindowEventArgs&)e).window)->getScrollPosition();
 val = ActiveShaderDef.convertScrollPositionToParam(val);
 setShaderControlVal( val, index );

 if(mActivePass)
 {
  switch(ActiveShaderDef.ValType)
  {
   //如果是VS或PS
   case GPU_VERTEX:
   case GPU_FRAGMENT:
    {
     GpuProgramParametersSharedPtr activeParameters =
      (ActiveShaderDef.ValType == GPU_VERTEX) ?
       mActiveVertexParameters : mActiveFragmentParameters;

     if(!activeParameters.isNull())
     {
      activeParameters->_writeRawConstant(
       ActiveShaderDef.PhysicalIndex + ActiveShaderDef.ElementIndex, val);
     }
    }
    break;
   //如果是镜面光
   case MAT_SPECULAR:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getSpecular());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setSpecular( OldSpec );
    }

    break;
   //如果是漫射光
   case MAT_DIFFUSE:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getDiffuse());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setDiffuse( OldSpec );
    }
    break;
   //如果是环境光
   case MAT_AMBIENT:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getAmbient());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setAmbient( OldSpec );
    }
    break;
   //如果是自发光
   case MAT_SHININESS:
    // get the specular values from the material pass
    mActivePass->setShininess( val );
    break;
  }
 }

    return true;
}

 

              综上源码分析,可知,本质上海洋的表现是依靠材质来达成的。关键是掌握如何调节材质中对应的VS.PS属性值。

分类: 未分类 标签: