Android游戏开发十日通(6)- 太空大战
今天要学习的是coscos2d-x官网索引的一篇初级游戏教程。作为小白的入门,再适合不过了。
资源文件下载
工程源码下载
大师的源码
环境:
lubuntu 13.10 32bit Android 4.1 cocos2d-x 2.2
下面就一步步来完成。
1.创建工程
创建项目
终端进入 cocos2d-x-2.2/tools/project-creator/ ,执行
./create_project.py -project SpaceGame -package com.maclab.SpaceGame -language cpp
在 /cocos2d-x-2.2/projects/SpaceGame 中就有创建好的各平台的工程模板。
修改proj.android 下build_native.sh,添加一行指定NDK_ROOT
在eclipse中导入proj.android 工程,记得不要勾Copy to Project into workspace.
如果之前未将 /cocos2d-x-2.2/cocos2dx/platform/android/java 导入,在这里要导入。
创建软链接,终端进入 pro.android,执行命令:
ln -s ../Resources ./Resources
在Eclipse中刷新工程,Resources文件夹就出现了。
换一个狂拽酷炫点的图标
将android工程中res文件夹下的icon.png换成这个就可以了。
在项目上右击,run as->android application
一切顺利的话工程就创建好了,如果没法运行,检查cocos2dx是否配置好。
2.拷贝资源文件
将下载好的资源文件挨个拷贝到Resources文件夹中,注意Classes 文件夹不要拷贝,fonts文件夹合并就好。
3.添加一个小飞机
先将HelloWorldScence.cpp中的
USING_NS_CC;
移动到HelloWorldScence.h中,这样定义成员的时候就不用老加上命名空间了。
首先在HelloWorld.h中添加两个成员:
private:CCSpriteBatchNode* batchNode;CCSprite* ship;
然后在init的时候初始化这俩个成员:
batchNode = CCSpriteBatchNode::create("Spritesheets/Sprites.pvr.ccz");this->addChild(batchNode);CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Spritesheets/Sprites.plist");ship = CCSprite::createWithSpriteFrameName("SpaceFlier_sm_1.png");ship->setPosition(ccp(origin.x + visibleSize.width * 0.1,origin.y + visibleSize.height * 0.5));batchNode->addChild(ship,1);
分别编译linux版本和android 版本 ,效果如下:
4.添加卷轴滚动的背景
在头文件中继续添加几个相关的private成员:
CCParallaxNode *backgroundNode;
CCSprite *spacedust1;
CCSprite *spacedust2;
CCSprite *planetsunrise;
CCSprite *galaxy;
CCSprite *spacialanomaly;
CCSprite *spacialanomaly2;
还是在init() 中对它们进行初始化,把整个场景搭建起来:
这里用到了CCParallaxNode类,用它来实现背景,可以加强背景的层次感,在进行背景卷动的时候,可以实现越近的背景卷动得越快,越远越慢。(想想在火车上 向外看窗外的景色)
// 1) Create the CCParallaxNodebackgroundNode = CCParallaxNode::create();this->addChild(backgroundNode, -1);// 2) Create the sprites will be added to the CCParallaxNodespacedust1 = CCSprite::create("Backgrounds/bg_front_spacedust.png");spacedust2 = CCSprite::create("Backgrounds/bg_front_spacedust.png");planetsunrise = CCSprite::create("Backgrounds/bg_planetsunrise.png");galaxy = CCSprite::create("Backgrounds/bg_galaxy.png");spacialanomaly = CCSprite::create("Backgrounds/bg_spacialanomaly.png");spacialanomaly2 = CCSprite::create("Backgrounds/bg_spacialanomaly2.png");// 3) Determine relative movement speeds for space dust and backgroundCCPoint dustSpeed = ccp(0.1, 0.1);CCPoint bgSpeed = ccp(0.05, 0.05);// 4) Add children to CCParallaxNodebackgroundNode->addChild(spacedust1, 0, dustSpeed, ccp(0,visibleSize.height/2) ); // 2backgroundNode->addChild(spacedust2, 0, dustSpeed, ccp( spacedust1->getContentSize().width,visibleSize.height/2));backgroundNode->addChild(galaxy, -1, bgSpeed, ccp(0, visibleSize.height * 0.7));backgroundNode->addChild(planetsunrise, -1 , bgSpeed, ccp(600, visibleSize.height * 0));backgroundNode->addChild(spacialanomaly, -1, bgSpeed, ccp(900, visibleSize.height * 0.3));backgroundNode->addChild(spacialanomaly2, -1, bgSpeed, ccp(1500, visibleSize.height * 0.9));
编译运行之后的效果:
5.卷动背景
原理就是每一Frame将背景向后移动一定的距离,也就是背景图片以一定的速度运动。
在头文件中添加update函数,将其声明为似有成员函数,这个函数是会自动调用的。
private:// scheduled Update void update(float dt);
函数实现如下:
void HelloWorld::update(float dt)
{CCPoint backgroundScrollVert = ccp(-1000,0);backgroundNode->setPosition(ccpAdd(backgroundNode->getPosition(), ccpMult(backgroundScrollVert, dt)));
}
在init()中添加一句
this->scheduleUpdate();
这样背景就会不断地往后走,造成飞机在往前飞的假象,但有个问题,背景跑一会儿之后就不见了,因为没有循环显示。
而CCParallaxNode也没有对应的循环的方法,这里就要自定义类了。这里自定义一个CCParallaxNodeExtras类,继承 CCParallaxNode。主要是添加一个 incrementOffset() 方法,用户实现循环显示。
CCParallaxNodeExtras.h
#ifndef Cocos2DxFirstIosSample_CCParallaxNodeExtras_h
#define Cocos2DxFirstIosSample_CCParallaxNodeExtras_h#include "cocos2d.h"USING_NS_CC;class CCParallaxNodeExtras : public CCParallaxNode {public :// Need to provide a constructor CCParallaxNodeExtras();// just to avoid ugly later cast and also for safetystatic CCParallaxNodeExtras * node();// Facility method (it’s expected to have it soon in COCOS2DX) void incrementOffset(CCPoint offset, CCNode* node);
} ; #endif
CCParallaxNodeExtras.cpp
#include "CCParallaxNodeExtras.h" // Hack to access CCPointObject (which is not a public class)
class CCPointObject : CCObject {CC_SYNTHESIZE(CCPoint, m_tRatio, Ratio)CC_SYNTHESIZE(CCPoint, m_tOffset, Offset)CC_SYNTHESIZE(CCNode *, m_pChild, Child) // weak ref
};// Need to provide a constructor
CCParallaxNodeExtras::CCParallaxNodeExtras() {CCParallaxNode(); // call parent constructor
}CCParallaxNodeExtras * CCParallaxNodeExtras::node() {return new CCParallaxNodeExtras();
}void CCParallaxNodeExtras::incrementOffset(CCPoint offset,CCNode* node){for( unsigned int i = 0; i < m_pParallaxArray->num; i++) {CCPointObject *point = (CCPointObject *)m_pParallaxArray->arr[i];CCNode * curNode = point->getChild();if( curNode->isEqual(node) ) {point->setOffset( ccpAdd(point->getOffset(), offset) );break;}}
}
在这里还定义了一个内部类CCPointObject,关于CC_SYNTHESIZEz这个宏
#define CC_PROPERTY(varType, varName, funName)\
protected: varType varName;\
public: virtual varType get##funName(void);\
public: virtual void set##funName(varType var);
incrementOffset函数的作用就是将子node移动一个偏移量。
对原HelloWorldScence.cpp进行一定的修改,首先backgroundNode的声明要修改:
CCParallaxNodeExtras *backgroundNode;
其初始化变为
backgroundNode = CCParallaxNodeExtras::node();
在update()的最后添加下面的代码作为检测,
CCArray *spaceDusts = CCArray::arrayWithCapacity(2) ;
spaceDusts->addObject(_spacedust1) ;
spaceDusts->addObject(_spacedust2) ;
for ( int ii = 0 ; ii <spaceDusts->count() ; ii++ ) {CCSprite * spaceDust = (CCSprite *)(spaceDusts->objectAtIndex(ii)) ;float xPosition = _backgroundNode->convertToWorldSpace(spaceDust->getPosition()).x ;float size = spaceDust->getContentSize().width ;if ( xPosition < -size ) {_backgroundNode->incrementOffset(ccp(spaceDust->getContentSize().width*2,0),spaceDust) ; }
}CCArray *backGrounds = CCArray::arrayWithCapacity(4) ;
backGrounds->addObject(_galaxy) ;
backGrounds->addObject(_planetsunrise) ;
backGrounds->addObject(_spacialanomaly) ;
backGrounds->addObject(_spacialanomaly2) ;
for ( int ii = 0 ; ii <backGrounds->count() ; ii++ ) {CCSprite * background = (CCSprite *)(backGrounds->objectAtIndex(ii)) ;float xPosition = _backgroundNode->convertToWorldSpace(background->getPosition()).x ;float size = background->getContentSize().width ;if ( xPosition < -size ) {_backgroundNode->incrementOffset(ccp(2000,0),background) ; }
}
修改proj.linux/MakeFile,将新添加的 cpp 索引进来。
SOURCES = main.cpp \../Classes/AppDelegate.cpp \../Classes/HelloWorldScene.cpp\../Classes/CCParallaxNodeExtras.cpp
编译运行
android版本的编译需要修改proj.android/jni/Android.mk
LOCAL_SRC_FILES := hellocpp/main.cpp \../../Classes/AppDelegate.cpp \../../Classes/HelloWorldScene.cpp\../../Classes/CCParallaxNodeExtras.cpp
5.夜空中最亮的星
我们还可以在场景中添加一些星空的效果,可以用内置的粒子系统来实现,在init() 的后面添加下面的语句:
//Add some starsHelloWorld::addChild(CCParticleSystemQuad::create("Particles/Stars1.plist"));HelloWorld::addChild(CCParticleSystemQuad::create("Particles/Stars2.plist"));HelloWorld::addChild(CCParticleSystemQuad::create("Particles/Stars3.plist"));
编译后运行
6.控制小飞机
这里用到了移动设备的重力传感器。cocos2d-x对加速计进行了封装,我们可以不用关心具体平台api,直接使用抽象后的加速计api就可以了。
首先是要实现基类的关于传感器的虚函数,在头文件中添加:
virtual void didAccelerate(CCAcceleration* pAccelerationValue);
然后在cpp中添加其实现:
void HelloWorld::didAccelerate(CCAcceleration* pAccelerationValue) {#define KFILTERINGFACTOR 0.1#define KRESTACCELX -0.6 #define KMAXDIFFY 0.2#define KMAXDIFFX 0.1double rollingX = 0.0;double rollingY = 0.0;// Cocos2DX inverts X and Y accelerometer depending on device orientation// in landscape mode right x=-y and y=x !!! (Strange and confusing choice)//exchange valuefloat tmp;tmp = pAccelerationValue->x;pAccelerationValue->x = pAccelerationValue->y;pAccelerationValue->y = tmp;rollingX = (pAccelerationValue->x * KFILTERINGFACTOR);rollingY = (pAccelerationValue->y * KFILTERINGFACTOR);float accelX = pAccelerationValue->x - rollingX;float accelY = pAccelerationValue->y - rollingY;CCSize winSize = CCDirector::sharedDirector()->getWinSize();float accelDiffx = accelX - KRESTACCELX;float accelDiffy = accelY;float accelFractionx = accelDiffx / KMAXDIFFX;float accelFractiony = accelDiffy / KMAXDIFFY;shipPointsPerSecY = 0.5 * winSize.height * accelFractionx;shipPointsPerSecX = 0.5 * winSize.width * accelFractiony;
}
这个函数在每次检测到传感器的信息之后就会回调,传回一个CCAcceleration对象,这里只要x方向的值就可以了。注意这里还对传感器的值进行了一定的处理,让小飞机有一种飞行的感觉,同时速度是和屏幕大小对应的,算是多设备匹配的一个trick。
接下来在update() 中更行飞船的位置,在后面添加下面的代码:
CCSize winSize = CCDirector::sharedDirector()->getWinSize();float maxY = winSize.height - ship->getContentSize().height/2;float minY = ship->getContentSize().height/2;float maxX = winSize.width - ship->getContentSize().width/2;float minX = ship->getContentSize().width/2;float diffy = (shipPointsPerSecY * dt);float diffx = (shipPointsPerSecX * dt);float newY = ship->getPosition().y + diffy;float newX = ship->getPosition().x + diffx;newY = MIN(MAX(newY, minY), maxY);newX = MIN(MAX(newX, minX), maxX);ship->setPosition(ccp(newX, newY));
最后就是启动传感器的检测了,在init()中添加:
this->setAccelerometerEnabled(true);
这个功能只能在真机中测试。
7.添加小行星
在HelloWorld.h中添加几个私有成员变量,
CCArray* asteroids;int nextAsteroid;float nextAsteroidSpawn;
第一个用来存储小行星,第二个用来索引,第三个用来记录小行星出现的间隔时间。
添加几个public辅助函数:
//For get random float valuefloat randomValueBetween(float low, float high);//Set visibility of Nodevoid setInvisible(CCNode * node);//Get millisecs current sys-timefloat getTimeTick();
在init()中对成员进行初始化:
//init asteroidsasteroids = new CCArray();//Store asteroidsfor(int i = 0; i < 15; ++i) {CCSprite *asteroid = CCSprite::createWithSpriteFrameName("asteroid.png");asteroid->setVisible(false);batchNode->addChild(asteroid);asteroids->addObject(asteroid);}nextAsteroid = 0;nextAsteroidSpawn = 0.0;
接下来是函数的实现,都比较简单。
float HelloWorld::randomValueBetween(float low, float high) {return (((float) 2 * rand() / 0xFFFFFFFFu) * (high - low)) + low;
}float HelloWorld::getTimeTick() {timeval time;gettimeofday(&time, NULL);unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec/1000);return (float) millisecs;
}void HelloWorld::setInvisible(CCNode * node) {node->setVisible(false);
}
最后在update()中更新小行星:
//Set asteroidsfloat curTimeMillis = getTimeTick();if (curTimeMillis > nextAsteroidSpawn) {float randMillisecs = randomValueBetween(0.20,1.0) * 1000;nextAsteroidSpawn = randMillisecs + curTimeMillis;float randY = randomValueBetween(0.0,winSize.height);float randDuration = randomValueBetween(2.0,10.0);CCSprite *asteroid = (CCSprite *)asteroids->objectAtIndex(nextAsteroid);nextAsteroid++;if (nextAsteroid >= (int)asteroids->count())nextAsteroid = 0;asteroid->stopAllActions();asteroid->setPosition( ccp(winSize.width+asteroid->getContentSize().width/2, randY));asteroid->setVisible(true);asteroid->runAction(CCSequence::create(CCMoveBy::create(randDuration, ccp(-winSize.width-asteroid->getContentSize().width, 0)), CCCallFuncN::create(this, callfuncN_selector(HelloWorld::setInvisible)), NULL // DO NOT FORGET TO TERMINATE WITH NULL (unexpected in C++)));}
编译运行。
8.发射激光
和小行星的添加类似,首先修改头文件
CCArray* shipLasers;int nextShipLaser;
在init中初始化:
//init lasersshipLasers = new CCArray();for(int i = 0; i < 5; ++i){CCSprite *shipLaser = CCSprite::createWithSpriteFrameName("laserbeam_blue.png");shipLaser->setVisible(false);batchNode->addChild(shipLaser);shipLasers->addObject(shipLaser);}this->setTouchEnabled(true);nextShipLaser = 0;
9.简单的碰撞检测
这里的碰撞检测包括两个部分:激光和小行星的碰撞,飞机和小行星的碰撞。
首先添加一个私有成员,用于记录飞机的生命值。
int lives;
在init()添加对其的初始化:
lives = 3;
在update()中添加检测的操作:
//Collision Detection//AsteroidsCCObject* asteroid;CCObject* shipLaser;CCARRAY_FOREACH(asteroids, asteroid){if (!((CCSprite *) asteroid)->isVisible() )continue;CCARRAY_FOREACH(shipLasers, shipLaser){if (!((CCSprite *) shipLaser)->isVisible())continue;if (((CCSprite *) shipLaser)->boundingBox().intersectsRect(((CCSprite *)asteroid)->boundingBox()) ) {((CCSprite *)shipLaser)->setVisible(false);((CCSprite *)asteroid)->setVisible(false);continue;}}if (ship->boundingBox().intersectsRect(((CCSprite *)asteroid)->boundingBox()) ) {((CCSprite *)asteroid)->setVisible(false);ship->runAction( CCBlink::create(1.0, 9));lives--;}}
运行的效果是子弹或者飞船碰到小行星,小行星都会消失,飞船的话会闪动。
10.终止游戏
理论上当飞机生命没有的时候,游戏就要结束了。
这里游戏的胜利条件是坚持了60s,失败条件是飞机被撞击了三次。
添加一个枚举声明,表示游戏结束的原因:
typedef enum {WIN,LOSE
} EndReason;
添加私有成员:
double gameOverTime;
bool gameOver;
还有两个相关的public 方法:
//Called when game endedvoid endScene(EndReason endReason);//Restart gamevoid restartTapped();
实现如下:
void HelloWorld::restartTapped() {CCDirector::sharedDirector()->replaceScene(CCTransitionZoomFlipX::create(0.5, this->scene()));// reschedulethis->scheduleUpdate();
}void HelloWorld::endScene( EndReason endReason ) {if (gameOver)return;gameOver = true;CCSize winSize = CCDirector::sharedDirector()->getWinSize();char message[10] = "You Win";if ( endReason == LOSE)strcpy(message,"You Lose");CCLabelBMFont * label ;label = CCLabelBMFont::create(message, "fonts/Arial.fnt");label->setScale(0.1);label->setPosition(ccp(winSize.width/2 , winSize.height*0.6));this->addChild(label);CCLabelBMFont * restartLabel;strcpy(message,"Restart");restartLabel = CCLabelBMFont::create(message, "fonts/Arial.fnt");CCMenuItemLabel *restartItem = CCMenuItemLabel::create(restartLabel, this, menu_selector(HelloWorld::restartTapped) );restartItem->setScale(0.1);restartItem->setPosition( ccp(winSize.width/2, winSize.height*0.4));CCMenu *menu = CCMenu::create(restartItem, NULL);menu->setPosition(CCPointZero);this->addChild(menu);// clear label and menurestartItem->runAction(CCScaleTo::create(0.5, 1.0));label ->runAction(CCScaleTo::create(0.5, 1.0));// Terminate update callbackthis->unscheduleUpdate();
}
当游戏结束的时候,调用endScence方法现实结束提示的文字和按钮,可以选择重新再来,调用restartTapped.
运行效果如下:
11.来点音效
游戏中的音效可以为游戏添色不少。
首先将苹果的caf格式转换成android支持的wav.终端cd到工程目录下的 Resources/Sounds ,执行下面的命令(事先装好ffmpeg)
ffmpeg -i SpaceGame.caf SpaceGame.wav
ffmpeg -i explosion_large.caf explosion_large.wav
ffmpeg -i laser_ship.caf laser_ship.wav
顺利的话Sounds文件夹下面就生成了转好码的音频文件了。
在HelloWorld.h 中添加头文件和命名空间:
#include "SimpleAudioEngine.h"using namespace CocosDenshion;
在init() 中加入对音效的初始化,这里播放背景乐,同时预加载小行星爆炸的音效和发射激光的音效。
SimpleAudioEngine::sharedEngine()->playBackgroundMusic("SpaceGame.wav",true);SimpleAudioEngine::sharedEngine()->preloadEffect("explosion_large.wav");SimpleAudioEngine::sharedEngine()->preloadEffect("laser_ship.wav");
在碰撞检测中对应位置加入
SimpleAudioEngine::sharedEngine()->playEffect("Sounds/explosion_large.wav");
播放爆炸的声音。
在触摸函数中添加
SimpleAudioEngine::sharedEngine()->playEffect("Sounds/laser_ship.wav");
播放发射激光的声音。
发现linux版本不能正常编译,报错:
fatal error: SimpleAudioEngine.h: No such file or directory compilation terminated.
修改proj.linux/MakeFile
EXECUTABLE = SpaceGameINCLUDES = -I.. -I../Classes \-I$(COCOS_ROOT)/CocosDenshion/includeSOURCES = main.cpp \../Classes/AppDelegate.cpp \../Classes/HelloWorldScene.cpp\../Classes/CCParallaxNodeExtras.cppCOCOS_ROOT = ../../..
include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mkSHAREDLIBS += -lcocos2d -lcocosdenshion
COCOS_LIBS = $(LIB_DIR)/libcocos2d.so$(TARGET): $(OBJECTS) $(STATICLIBS) $(COCOS_LIBS) $(CORE_MAKEFILE_LIST)@mkdir -p $(@D)$(LOG_LINK)$(CXX) $(CXXFLAGS) $(OBJECTS) -o $@ $(SHAREDLIBS) $(STATICLIBS)$(OBJ_DIR)/%.o: %.cpp $(CORE_MAKEFILE_LIST)@mkdir -p $(@D)$(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST)@mkdir -p $(@D)$(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@
主要是搜索路径和库的链接。然后linux版本就可以编译了。
android版本直接编译运行即可。
到此为止,已经基本完成了一个声色俱全的移动平台游戏了~
To be continue
可以做的还有很多,比如
1.给飞机添加血量的显示;
2.添加爆炸的动画;
3.添加敌机;
4.遭遇大boss
...
参考
Cocos2D-X Tutorial for iOS and Android: Space Game
Android游戏开发十日通(6)- 太空大战相关推荐
- Android游戏开发十日通(7)- 开发一个双人游戏
提要 游戏需要分享才能获得快乐,想想你以前玩过的那些游戏,那些会是真正地存在你婶婶的脑海里?是独自一人躲在被窝里酣战PSP,还是和哥们在网吧一起开黑?是一个人单刷迅龙三连,还是和朋友联机怒刷黄黑龙? ...
- 【ANDROID游戏开发十六】ANDROID GESTURE之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html - ...
- 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!
李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/331.html 很多童鞋说 ...
- 【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputStream/FileOutputStream将数据存储到SD卡中!
李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/327.html 很多童鞋说 ...
- 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/331.html 之 ...
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html ...
- 【Android游戏开发十八】解放手指,利用传感器开发游戏!
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/344.html 前 ...
- 【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)
本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...
- 【Android游戏开发十五】关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记! .
http://blog.csdn.net/xiaominghimi/article/details/6127578 http://www.androidegg.com/portal.php?mod=v ...
最新文章
- 2022-2028年中国清水混凝土行业供需策略分析及市场供需预测报告
- java javaw区别
- 学习日记-类继承中的上下转换
- Unicorn - W3C 统一验证工具
- oracle自动备份定时任务,Oracle数据库定时自动备份批处理代码(Windows)
- java character是什么意思_Java Character 类
- python200行代码小游戏_200 行python 代码实现 2048 游戏
- java删除文件中的一行_在Linux中使用java和javac命令编译运行java文件
- app 缓存html页面,HTML5本地存储VS App缓存离线网站浏览
- 从ASP.NET的PHP执行速度比较谈起
- 2017 Multi-University Training Contest - Team 7:1008. Hard challenge(模拟)
- python: 大规模数据集的读存技巧
- 我买的开发板——大虾网DX32(for STM32)
- 计算机桌面颜色如何设置标准,电脑桌面背景字体颜色设置小技巧
- 新浪微博开放平台注册样例
- Arduino应用开发——TCP/IP无线传输
- 关于使用stm8单片机的“外部计数”TIMx_ETR测脉冲的软件配置问题!
- python金融大数据分析师工资待遇_三年工作经验大佬带你解读 Python金融大数据分析...
- 专利修改:solidworks出线条图
- 【asp.net core 系列】5 布局页和静态资源