iOS – 团队协作开发总结

实际团队协作开发中会与独立开发有些需要注意的地方,总结了一下。

页面UI设计

建议不要使用Storyboard或者XibFile之类的,不容易维护不容易复用,最好全部采用程序编码来实现所有页面的UI布局。

SVN

project.pbxproj这个文件经常冲突,这里有一个很好用的脚本分享给大家吧:D

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
projectfile=`find -d . -name 'project.pbxproj'`
projectdir=`echo *.xcodeproj`
projectfile="${projectdir}/project.pbxproj"
tempfile="${projectdir}/project.pbxproj.out"
savefile="${projectdir}/project.pbxproj.mergesave"
#cat $projectfile | grep -v "<<<<<<< HEAD" | grep -v "=======" | grep -v "^>>>>>>> " > $tempfile
cat $projectfile | grep -v "<<<<<<<" | grep -v "=======" | grep -v "^>>>>>>> " > $tempfile
cp $projectfile $savefile
mv $tempfile $projectfile

游戏作品 – 《方块喵的世界》

游戏名称:方块喵的世界
英文名称:Miao Craft
游戏类型:3D沙盒游戏
游戏制作:Megatron’s Lab
游戏发行:MC Games
游戏平台:PC
官方网址:imegatron.com

游戏介绍:

《方块喵的世界》是一款3D沙盒游戏,挖矿、养鸡、盖房子、抵抗僵尸,完全是经典游戏MineCraft的C++版本,本作会将游戏的优化进行到底,让所有热爱这款游戏的玩家尽情地享受流畅的游戏体验。

在游戏里,太阳是方的,云是方的,所有的东西都是方方的,哈哈!玩家一开始出生在一个随机的地点,因为石头比较硬,可以先采集一些木材来修建一个小房子来度过第一个晚上,白天灼热的阳光会把僵尸烧着,所以一到夜晚各种怪物们就会出来溜达了,如果实在没来及修好墙,就在泥土地上挖一个洞钻进去后再把洞口堵上也能将就着过一晚哈哈!游戏的地图没有边界,只要你还能找到回家的路。没事可以盖个漂亮的大房子,如果挖到红石矿就可以合成很多电器元件神马的,活塞啊、电路啊、开关啊等着你来研究呢。也可以去地下的超大矿洞里去探险,矿洞里还是很恐怖的,一个人探险需要很小心,因为下面没有阳光,僵尸的叫声远远就可以听到。。。多人游戏还可以建立一个村落,然后修条铁路通往最近的“大城市”,总之玩法多样,游戏也没有关卡神马的,只要你愿意就可以酱紫无限制地玩下去,这也许就是这种沙盒类游戏的魅力所在吧。

预告视频:

下载地址:

官方本地下载1 官方本地下载2

游戏作品 – 《喵星冒险记OL》

游戏名称:喵星冒险记OL
英文名称:Miao Star Adventure
游戏类型:3D多人在线角色扮演
游戏制作:Megatron’s Lab
游戏发行:MC Games
游戏平台:PC
官方网址:imegatron.com

游戏介绍:

《喵星冒险记OnLine》是一款3D多人在线角色扮演(MMORPG)游戏,全新的OGRE3D图形引擎将带来震撼的3D渲染效果,新的3D骨骼动画技术让我们的喵星人活灵活现,加上炫丽的场景、丰富的任务、波澜的剧情、强大的武器装备、真实的战斗数据和完善的等级系统让我们的喵星之旅充满欢乐也不乏挑战。

预告视频:

下载地址:

官方本地下载1 官方本地下载2

游戏作品 – 《切图喵》

游戏名称:切图喵
英文名称:Miao Cutter
游戏类型:2D休闲
游戏制作:Megatron’s Lab
游戏发行:MC Games
游戏平台:PC
官方网址:imegatron.com

游戏介绍:

《切图喵》是一款2D桌面休闲游戏,每一关玩家将控制切图喵,在地图上躲开敌人巡逻的守卫,用神奇的喵星人画笔划出永久属于自己的领地区域即可过关。值得一提的是这里有丰富的美喵图片可以让玩家们在休闲娱乐之时也不耽误欣赏众喵们的美色:D

预告视频:

下载地址:

官方本地下载1 官方本地下载2

@bitbucket.org

游戏作品 – 《喵星争霸》

游戏名称:喵星争霸
英文名称:Miao Star Craft
游戏类型:RTS
游戏制作:Megatron’s Lab
游戏发行:MC Games
游戏平台:PC
官方网址:imegatron.com

游戏介绍:

《喵星争霸》是一款2D斜45度角即时战略游戏,人工智能方面采用了强大的A*寻路算法,喵们都说自从用了A*,走路再也不怕撞墙了,哈哈!由于是采用了自行研发的图形引擎,针对各平台深度优化,低配机器照样可以流畅游戏!

游戏发生在距离地球五百二十一万光年的喵星上,这里曾是美丽富饶的地方,上百万的喵星人在这个星球上安逸地生活着,但是他们平静的生活很快将会被一场神秘外星人(来自机械种族的收割者)的入侵打破,这些神秘外星人来到喵星后烧杀抢掠无恶不作,一向我行我素低调做事的喵星人终于怒了,他们团结了起来,拿起武器,决定誓死保卫家园!玩家将扮演喵星人的指挥官,指挥着勇敢的喵星人与坏人们战斗。

预告视频:

下载地址:

官方本地下载1 官方本地下载2

@bitbucket.org

iOS – 各种手势的处理

Swipe(滑动屏幕)

  1. 定义两个关键的变量
1
2
UISwipeGestureRecognizer *leftSwipeGestureRecognizer;
UISwipeGestureRecognizer *rightSwipeGestureRecognizer;
  1. 初始化它们
1
2
3
4
5
6
leftSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipes:)];
rightSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipes:)];
leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:leftSwipeGestureRecognizer];
[self.view addGestureRecognizer:rightSwipeGestureRecognizer];
  1. 添加Actions
1
2
3
4
5
6
7
8
9
- (void)handleSwipes:(UISwipeGestureRecognizer *)sender
{
if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(@"UISwipeGestureRecognizerDirectionLeft");
}
if (sender.direction == UISwipeGestureRecognizerDirectionRight) {
NSLog(@"UISwipeGestureRecognizerDirectionRight");
}
}

Pan(拖动)

  1. 定义一个变量
1
UIPanGestureRecognizer *panRecognizer;
  1. 初始化
1
2
3
panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(didPan:)];
[self.view addGestureRecognizer:panRecognizer];//!!!!注意这里,view和它所有的子View都会被加上!!!!
panRecognizer.maximumNumberOfTouches = 1;
  1. 添加Actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- (void)didPan:(UIPanGestureRecognizer *)panGesture{
CGPoint point = [panGesture translationInView:self];
NSLog(@"%f,%f", point.x, point.y);
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:{
NSLog(@"UIGestureRecognizerStateBegan");
} break;
case UIGestureRecognizerStateEnded:{
NSLog(@"UIGestureRecognizerStateEnded");
} break;
case UIGestureRecognizerStateCancelled:{
NSLog(@"UIGestureRecognizerStateCancelled");
} break;
default:
break;
}
theView.frame = CGRectMake(0,
y,
theView.bounds.size.width,
theView.bounds.size.height);
[panGesture setTranslation:CGPointMake(0, 0) inView:self];
}

总结

UISwipeGestureRecognizer 和 UIPanGestureRecognizer 都是 UIGestureRecognizer 的子类,它们针对了不同类型的手势。

iOS – 娱乐解说手动内存管理的各种坑

废话少说,让我们开始吧。;)

情景一:初始化

1
self.varX = [NSObject alloc]init];//错误

总结:在用alloc]init]消息初始化时,左值一定不要使用set方法获取,

情景二:release

谁用了使retainCount加1的操作(如alloc、retain等),谁就要负责释放。

情景三:retain

设置实例变量时,如果右值没有retainCount加1的副作用,就一定要记得手动retain。

例子1:

1
btnImage = [[UIImage ImageNamed@"imgname"]retain];//正确

例子2:

1
2
3
- (void)modCell:(UserInfo *)info{
cellInfo = [info retain];//cellInfo是实例变量
}

例子3:

同例子2类似,但是如果左值本身带有retainCount加1的副作用,就可以不用在手动retain。
比如:

1
2
3
- (void)modCell:(UserInfo *)info{
self.cellInfo = info;//cellInfo是实例变量
}

再比如:

1
2
3
- (void)modCell:(UserInfo *)info{
objectB.cellInfo = info;//cellInfo和objectB都是strong类型
}

情境四:数组

1
2
3
listItemArray = @[@[@"如何充值?", @"145"],
@[@"如何提现?", @"395"],];
[listItemArray retain];

最后:

原理是一样的,就是要保持retainCount的加1操作和减1操作的平衡,以不至于导致对象提前释放或者内存泄露的问题。但是一到实战还是会掉一些坑的,在哪个坑掉进去,就从哪里爬出来,祝大家编程愉快!:D

iOS – isKindofClass 与 isMemberofClass 的区别

这两个消息看起来有点像,不熟悉的话,会用错哦:D

isKindofClass消息

1
2
3
if ( [objectA isKindOfClass:[ClassA class]] ){
//objectA的类是ClassA或ClassA的子类。
}

isMemberofClass消息

1
2
3
if ( [objectA isMemberofClass:[ClassA class]] ){
//objectA的类是ClassA。
}

Good Luck! :D

iOS – 单例(singleton)的实现

很多时候,一些类我们只需要它们只有一个全局实例,在 Objective-C 语言中,我们可以这样实现单例模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma mark - Singleton
+ (ClassA *)sharedInstanceOfTom{
static ClassA *sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(void){
sharedSingleton = [[self alloc]init];
});
return sharedSingleton;
}
+ (ClassA *)sharedInstanceOfJerry{
static ClassA *sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(void){
sharedSingleton = [[self alloc]init];
});
return sharedSingleton;
}

然后在用到这个单例的地方,我们只需要包含该头文件,然后调用:

1
2
3
#import "ClassA.h"
[ClassA sharedInstanceOfTom].name = @"Tom";
[ClassA sharedInstanceOfTom].age = 29;

是不是很简单呵呵:D

MISS – 我的大黄猫

大黄,你咋返老还童了。。。

iOS – UIScrollView嵌套之妙用

情景

有时界面中会需要一种稍微特别一点点的滚动区,在主滚动区有要显示的主要内容,当向上滚动到顶部时,再继续向下拖拽就能把主滚动区整体往下拖动,从而显示出背景层的一些信息,或者另外一个View区。

思考各种方案

实现这种效果有很多种办法,可以增加一层透明的手势层来手动处理所有拖动,这里涉及到一些事件的触发回调优先级和继承关系,还有要手动处理滚动加速动画效果。

下面要跟大家分享一个很巧妙的方法,半夜睡前来的灵感,然后马上重新打开电脑实现之:D

分享

这个方法说起来倒是很简单很简单,嗯,嗯,就是在一个 UIScrollView 中再嵌套一个 UIScrollView 就OK啦,是不是很简单,可是我会说在想出这个办法之前,如何能很好的解决这个问题已经困扰了我两三天的时间嘛呵呵~

具体的,只要写一个相应的 UIScrollViewDelegate,在里面判断一些位置,关掉或打开主滚动区的 scrollEnabled 属性就可以了。

iOS – 工程中的资源文件管理总结

图片资源

有时项目组内部不使用Images.xcassets管理,图片资源文件名可以命名为: image_name@2x.png
直接加到工程目录下,在工程中对其引用时只需调用:

1
[UIImage imageNamed:@"image_name"]

这样,如果是非Retina屏,系统会自动为其缩放,当然如果你想节省点cpu,可以同时再加入一个: image_name.png

Ogre3d官网中级教程八源代码不能正常编译的问题

Ogre3d Intermediate Tutorial 8 中提供的源代码不能正常编译的问题,其实只要仔细查找就可以发现具体原因,我自己总结了一下,并将可以正常编译使用的源代码共享出来,希望能给初学Ogre3d而在这里遇到问题的同学提供一点参考。

1、用OIS的输入库来代替“InputReader* mInputDevice;”如下:

1
2
3
4
OIS::InputManager* mInputManager;
OIS::Mouse* mMouse;
OIS::Keyboard* mKeyboard;
OIS::JoyStick* mJoy;

初始化OIS输入时用下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
OIS::ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
mInputManager = OIS::InputManager::createInputSystem( pl );
//Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, false ));
try {
mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, false ));
}
catch(...) {
mJoy = 0;
}

另外还有处理输入的函数processUnbufferedKeyInput()中也要修改相关代码,在processUnbufferedMouseInput()中要用OIS的输入代替原来的,可用下面的代码:

1
2
3
4
5
6
7
8
9
10
11
const OIS::MouseState &ms = mMouse->getMouseState();
if( ms.buttonDown( OIS::MB_Right ) )
{
mTranslateVector.x += ms.X.rel * 0.13;
mTranslateVector.y -= ms.Y.rel * 0.13;
}
else
{
mRotX = Degree(-ms.X.rel * 0.13);
mRotY = Degree(-ms.Y.rel * 0.13);
}

相应的修改还有:

1
2
3
// mInputDevice->capture();
mKeyboard->capture();
mMouse->capture();

还有几个类似的地方都要修改,总之,与“mInputDevice”相关的都用OIS库来代替,很容易理解吧:D

2、用“Root::getSingletonPtr()”来代替所有的“mRoot”指针。

3、在“OgreApplication”类文件中添加变量定义:“protected: std::string mDebugText;”,相应的,所有mWindow->getDebugText()或mWindow->setDebugText()可均直接使用mDebugText变量来代替(当然,如果你想写操作似有变量的函数getDebugText()和setDebugText()更好~)。

4、MyApplication.cpp文件中的宏使用“SET_TERM_HANDLER;”如果用不着可以注释掉。

最后不罗嗦了,喜欢直接拷贝源代码的同学请看下面:)

文件“OgreApplication.h”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifndef __OgreApplication_h__
#define __OgreApplication_h__
#include <ogre.h>
#include <OIS/OIS.h>
using namespace Ogre;
class OgreApplication : public FrameListener
{
public:
OgreApplication(void);
virtual ~OgreApplication(void);
virtual void go(void);
protected:
virtual bool initialise();
virtual bool initOgreCore();
virtual void createSceneManager();
virtual void createCamera();
virtual void createViewports();
virtual void createResourceListener();
virtual void createFrameListener();
virtual void addResourceLocations();
virtual void initResources();
virtual void createScene() = 0; // I am pure virtual, override me!
virtual void destroyScene();
virtual void updateStats();
void showDebugOverlay(bool show);
virtual void moveCamera();
virtual bool processUnbufferedKeyInput(const FrameEvent &evt);
virtual bool processUnbufferedMouseInput(const FrameEvent &evt);
// FrameListener overrides
virtual bool frameStarted(const FrameEvent &evt);
virtual bool frameEnded(const FrameEvent &evt);
Camera *mCamera;
SceneManager *mSceneMgr;
RenderWindow *mWindow;
Real mMoveSpeed;
Degree mRotateSpeed;
Overlay *mDebugOverlay;
Vector3 mTranslateVector;
float mMoveScale;
Degree mRotScale;
Radian mRotX, mRotY;
//InputReader* mInputDevice;
//OIS Input devices
OIS::InputManager* mInputManager;
OIS::Mouse* mMouse;
OIS::Keyboard* mKeyboard;
OIS::JoyStick* mJoy;
std::string mDebugText;
private:
Real mTimeUntilNextToggle;
int mSceneDetailIndex;
bool mStatsOn;
unsigned int mNumScreenShots;
TextureFilterOptions mFiltering;
int mAniso;
};
#endif // __OgreApplication_h__

文件“OgreApplication.cpp”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#include "OgreApplication.h"
//--------------------------------------------------------------------------------------------------
OgreApplication::OgreApplication()
{
}
//--------------------------------------------------------------------------------------------------
OgreApplication::~OgreApplication()
{
//PlatformManager::getSingleton().destroyInputReader(mInputDevice);
delete Root::getSingletonPtr();
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::addResourceLocations()
{
// Load resource paths from config file
ConfigFile cf;
cf.load("resources.cfg");
// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();
String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::initOgreCore()
{
// Show the configuration dialog and initialise the system
// You can skip this and use root.restoreConfig() to load configuration
// settings if you were sure there are valid on<wbr>es saved in ogre.cfg
if ( Root::getSingletonPtr()->restoreConfig() || Root::getSingletonPtr()->showConfigDialog())
{
// If returned true, user clicked OK so initialise
// Here we choose to let the system create a default rendering window by passing 'true'
mWindow = Root::getSingletonPtr()->initialise(true);
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::createSceneManager()
{
// Create the SceneManager, in this case a generic on<wbr>e
mSceneMgr = Root::getSingletonPtr()->createSceneManager(ST_GENERIC);
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::createCamera()
{
// Create the camera
mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at 500 in Z direction
mCamera->setPosition(Vector3(0,0,500));
// Look back along -Z
mCamera->lookAt(Vector3(0,0,-300));
mCamera->setNearClipDistance(5);
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::createViewports()
{
// Create on<wbr>e viewport, entire window
Viewport *vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::createResourceListener()
{
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::initResources()
{
// Initialise, parse scripts etc
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::destroyScene()
{
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::createFrameListener()
{
mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
mRotateSpeed = 36;
mMoveSpeed = 100;
// 初始化输入系统
//mInputDevice = PlatformManager::getSingleton().createInputReader();
//mInputDevice->initialise(mWindow,true, true);
OIS::ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
mInputManager = OIS::InputManager::createInputSystem( pl );
//Create all devices (We on<wbr>ly catch joystick exceptions here, as, most people have Key/Mouse)
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, false ));
try {
mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, false ));
}
catch(...) {
mJoy = 0;
}
mStatsOn = true;
mNumScreenShots = 0;
mTimeUntilNextToggle = 0;
mSceneDetailIndex = 0;
mMoveScale = 0.0f;
mRotScale = 0.0f;
mTranslateVector = Vector3::ZERO;
mAniso = 1;
mFiltering = TFO_BILINEAR;
showDebugOverlay(true);
Root::getSingletonPtr()->addFrameListener(this);
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::go()
{
if (!initialise())
return;
Root::getSingletonPtr()->startRendering();
// clean up
destroyScene();
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::initialise()
{
new Root();
// add resource locations
addResourceLocations();
// if we cannot initialise Ogre, just abandon the whole deal
if (!initOgreCore())
return false;
createSceneManager();
createCamera();
createViewports();
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// Create any resource listeners (for loading screens)
createResourceListener();
// Initialise resources
initResources();
// Create the scene
createScene();
createFrameListener();
return true;
};
//--------------------------------------------------------------------------------------------------
void OgreApplication::updateStats()
{
static String currFps = "Current FPS:";
static String avgFps = "Average FPS:";
static String bestFps = "Best FPS:";
static String worstFps = "Worst FPS:";
static String tris = "Triangle Count:";
// update stats when necessary
try{
OverlayElement *guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
OverlayElement *guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
OverlayElement *guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
OverlayElement *guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
const RenderTarget::FrameStats &stats = mWindow->getStatistics();
guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
+" "+StringConverter::toString(stats.bestFrameTime)+" ms");
guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
+" "+StringConverter::toString(stats.worstFrameTime)+" ms");
OverlayElement *guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
OverlayElement *guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
guiDbg->setCaption(mDebugText);
}
catch(...)
{
// ignore
}
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::processUnbufferedKeyInput(const FrameEvent &evt)
{
if(mKeyboard->isKeyDown(OIS::KC_A))
mTranslateVector.x = -mMoveScale;&nbsp;// Move camera left
if(mKeyboard->isKeyDown(OIS::KC_D))
mTranslateVector.x = mMoveScale;&nbsp;// Move camera RIGHT
if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
mTranslateVector.z = -mMoveScale;&nbsp;// Move camera forward
if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
mTranslateVector.z = mMoveScale;&nbsp;// Move camera backward
if(mKeyboard->isKeyDown(OIS::KC_PGUP))
mTranslateVector.y = mMoveScale;&nbsp;// Move camera up
if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
mTranslateVector.y = -mMoveScale;&nbsp;// Move camera down
if(mKeyboard->isKeyDown(OIS::KC_RIGHT))
mCamera->yaw(-mRotScale);
if(mKeyboard->isKeyDown(OIS::KC_LEFT))
mCamera->yaw(mRotScale);
if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )
return false;
if( mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 )
{
mStatsOn = !mStatsOn;
showDebugOverlay(mStatsOn);
mTimeUntilNextToggle = 1;
}
if( mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 )
{
switch(mFiltering)
{
case TFO_BILINEAR:
mFiltering = TFO_TRILINEAR;
mAniso = 1;
break;
case TFO_TRILINEAR:
mFiltering = TFO_ANISOTROPIC;
mAniso = 8;
break;
case TFO_ANISOTROPIC:
mFiltering = TFO_BILINEAR;
mAniso = 1;
break;
default: break;
}
MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
showDebugOverlay(mStatsOn);
mTimeUntilNextToggle = 1;
}
if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)
{
std::ostringstream ss;
ss << "screenshot_" << ++mNumScreenShots << ".png";
mWindow->writeContentsToFile(ss.str());
mTimeUntilNextToggle = 0.5;
mDebugText = "Saved: " + ss.str();
}
if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)
{
mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
switch(mSceneDetailIndex) {
case 0 : mCamera->setPolygonMode(PM_SOLID); break;
case 1 : mCamera->setPolygonMode(PM_WIREFRAME); break;
case 2 : mCamera->setPolygonMode(PM_POINTS); break;
}
mTimeUntilNextToggle = 0.5;
}
static bool displayCameraDetails = false;
if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)
{
displayCameraDetails = !displayCameraDetails;
mTimeUntilNextToggle = 0.5;
if (!displayCameraDetails)
mDebugText = "";
}
if (displayCameraDetails)
{
// Print camera details
mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
" " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());
}
// Return true to continue rendering
return true;
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::processUnbufferedMouseInput(const FrameEvent &evt)
{
/* Rotation factors, may not be used if the second mouse button is pressed. */
/* If the second mouse button is pressed, then the mouse movement results in
sliding the camera, otherwise we rotate. */
const OIS::MouseState &ms = mMouse->getMouseState();
if( ms.buttonDown( OIS::MB_Right ) )
{
mTranslateVector.x += ms.X.rel * 0.13;
mTranslateVector.y -= ms.Y.rel * 0.13;
}
else
{
mRotX = Degree(-ms.X.rel * 0.13);
mRotY = Degree(-ms.Y.rel * 0.13);
}
return true;
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::moveCamera()
{
// Make all the changes to the camera
// Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW(e.g.airplane)
mCamera->yaw(mRotX);
mCamera->pitch(mRotY);
mCamera->moveRelative(mTranslateVector);
}
//--------------------------------------------------------------------------------------------------
void OgreApplication::showDebugOverlay(bool show)
{
if(mDebugOverlay)
{
if(show)
{
mDebugOverlay->show();
}
else
{
mDebugOverlay->hide();
}
}
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::frameStarted(const FrameEvent &evt)
{
if(mWindow->isClosed())
return false;
if (mTimeUntilNextToggle >= 0)
mTimeUntilNextToggle -= evt.timeSinceLastFrame;
// If this is the first frame, pick a speed
if (evt.timeSinceLastFrame == 0)
{
mMoveScale = 1;
mRotScale = 0.1;
}
// Otherwise scale movement units by time passed since last frame
else
{
// Move about 100 units per second,
mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
// Take about 10 seconds for full rotation
mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
}
mRotX = 0;
mRotY = 0;
mTranslateVector = Vector3::ZERO;
//&nbsp;mInputDevice->capture();
mKeyboard->capture();
mMouse->capture();
if(processUnbufferedKeyInput(evt)==false)
return false;
if(processUnbufferedMouseInput(evt)==false)
return false;
moveCamera();
return true;
}
//--------------------------------------------------------------------------------------------------
bool OgreApplication::frameEnded(const FrameEvent &evt)
{
updateStats();
return true;
}

文件“MyApplication.cpp”:

不喜欢的话就直接注释掉这一行也可以的:D

1
//SET_TERM_HANDLER;

同一语句在不同地方调用,效率也不同

最近在优化游戏《切图》时,发现主要算法中的瓶颈总是找不到,最后自己用GetTickCount()分级别测试了运行中的函数,最后终于发现瓶颈竟然在一个不很起眼的多边形面积计算函数上,游戏主循环函数用了900毫秒,其中这个计算面积的函数就用掉了全部的900毫秒,罪魁祸首啊,还不把它揪出来!:[仔细分析后暂时得出以下结论作为经验和教训,但该问题有待于必要时进一步的研究.

看下面的语句:

1
if ( color == ((USHORT *)back_buffer)[pt2.x + pt2.y*(back_lpitch >> 1)] )

这是一个简单的视频缓冲区象素级访问的一条语句,该语句用来判断当前视频缓冲中位置 pt2 的颜色是否跟 color 相同.用GetTickCount()函数可以测试出该语句在我的机器上调用时消耗的时间不足1毫秒,但是再看下面的语句:

1
2
3
4
5
6
7
8
9
10
for (int scan_y=y1; scan_y<=y2; scan_y++)
{
for (int scan_x=x1; scan_x<=x2; scan_x++)
{
if ( color == ((USHORT *)back_buffer)[scan_x + scan_y*(back_lpitch >> 1)] ) // 注意这条语句
area++;
} // end for x
// move down a line
scan_buffer2+=scan_lpitch;
} // end for y

在循环里的这条相同的语句用GetTickCount()函数测试发现它最多时会消耗16毫秒的时间.
如此大的差异是怎么产生的呢?经初步分析应该是体系结构课程里面讲到的”缓冲命中”问题,在这里,双重的深度循环用来索引大数组很容易产生不能命中的情况,于是上面的事情就发生了.

附:找到的一个很好的求多边形面积的算法.
假设n边形按顺序的点p0, p1, p2…pn保存在数组p[n]中,

1
2
3
4
5
6
7
float area = 0;
for (int i=0, j=1; i<n; i++, j++)
{
j = j % n;
area += p[i].x*p[j].y - p[i].y*p[j].x;
}
area = fabs( area * 0.5 );

帅吧,吼吼:D

总结 – 红警2 相关问题

这款游戏应该比较经典了吧呵呵~和大家联机玩时有时会有些问题,总结了一下

联机问题:

1,IPX协议要装,连网的每台都要装,具体做法—— 网络连接属性里,本地连接属性,点安装,找到IPX协议安装上就可以了。

2,游戏序列号要改,连网的每台都要不同,具体做法—— 游戏目录里有一个名叫“Woldata.key”的文件,用记事本打开,把最后两位数字改了就行了,每台不同)如果打开后是乱码,把我下面给出的复制进去替换原来的字符—— 10991478310537…2319061240\SETUP.INI 把最后两位数“40”每台改成不同的就可以了

3,设置目标网络,连网的每台都要相同,具体做法—— 进 入游戏后,点选项,网络设置,在“目标网络”上填写好,如:“00.00.00.00”或“56.78.12.34”等等,八位数字三个点,一样就可以 了。(关于这里我的经验是,只要选择“选项”—>“网络”里面的第一个“网络卡”,选第二个,“000000。。。。。”的就ok了

ok,所有步骤完毕,有时可能还无法连机,那么重新启动一下就可以了

另外,有高配机器玩红警2卡的问题或者玩不了的问题,可尝试将显卡的相关加速功能禁用,具体做法:开始—>运行—>dxdiag,在“显示”标签页,将DirectDraw 加速 禁用掉,在玩其他3D游戏时再将其开启即可。此法也适用于其它一些老游戏,如绝地风暴等等。

对了还有谁在玩ra95的没,那个怎么联知道的分享一下吧~