【Cocos游戏实战】功夫小子第七课之游戏主功能场景逻辑功能和暂停功能场景的分析和实现
CSDN的markdown编辑器是吃屎了么!
!。什么玩意。!写了一半写不了东西还全没了,搞个毛线!
本节课的视频教程地址是:第七课在此
假设本教程有帮助到您,希望您能点击进去观看一下,并且如今注冊成为极客学院的会员,能够免费领取30天学习时间,免费拿极客学院VIP,1000+高清视频。学习Android、HTML5、iOS各种开发技术,限时领取。手快的戳:http://e.jikexueyuan.com/invite/index.html?ZnJvbV9jb2RlPVkxblJUZSZ1bmFtZT1TdW9vTCZjaGFubmVsPWludml0ZV8xMDB3X3NoYXJlYnV0dG9uX2RpcmVjdDE=。验证手机号码和邮箱号码会赠送三天的会员时间。手机端首次也能够领取五天的会员时间哦(即使是购买年会员眼下也不过年费260)。成为极客学院学习会员能够无限制的下载和观看全部的学院站点的视频。谢谢您的支持!
转载请注明出处:http://blog.csdn.net/suool/article/details/47128637
不想再重写一遍了。简短点。这节课要实现和学习的内容有:(假设想看具体内容的请戳上面的连接,看下视频的教程更好)
1.人物的运动状态控制——跳起。受伤,死亡推断。和怪物的打斗逻辑
2.碰撞检測(我们这个游戏因为是横版且人物仅仅可以在左右走。因此变化的坐标仅仅有X,所以检測起来也是非常easy的。
)
很多其它关于碰撞检測的东西见:http://shahdza.blog.51cto.com/2410787/1548097
3.关卡的失败和胜利推断以及相关的场景的分析和实现
4.暂停功能场景的分析和实现
关于跳起的动作这里简单的解释一下。
由于要模拟人物跳起后的一个近抛物线的运动轨迹,因此我们这里让Y轴的速度不断变化,而X轴不变,这个原理学过高中物理应该都明确。
这个函数就是:
float velocity = 0.0f; // 跳起速度
float getVelocity(); // 获取跳跃的速度
逻辑的东西解释起来比較复杂,先把代码贴出来吧。
/*!
* \file GameLayer.h
* \date 2015/06/13 16:55
*
* \author SuooL
* Contact: hu1020935219@gmail.com
*
* \brief 游戏场景
*
* TODO: long description
*
* \note
*/ #ifndef __GameLayer__H__
#define __GameLayer__H__ #include <iostream>
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
#include "ActionTool.h"
#include "GlobalData.h"
#include "GlobalDefine.h"
#include "extensions/cocos-ext.h"
#include "Monster.h" USING_NS_CC;
using namespace extension; class Hero;
class ProgressBar;
class GameMap; class GameLayer : public Layer
{
public: static Scene* createScene();
virtual bool init(); // 暂停
void gamePause(Ref* pSender); void gameOver(float delta);
void gameVictory(float delta);
// 技能--拳击--脚踢--超级技能--蹦
void fistAttack(Ref* pSender, Control::EventType type);
void footAttack(Ref* psender, Control::EventType type);
void comboAttack(Ref* pSender, Control::EventType type);
void jump(Ref* pSender, Control::EventType type); // 前进,后退
void forward(Ref* pSender, Control::EventType type);
void backward(Ref* pSender, Control::EventType type); bool isAttackMonster(Hero * hero, Monster* monster); virtual void update(float delta); CREATE_FUNC(GameLayer); private: // 英雄&怪物
Hero* m_pHero;
Monster* m_pMonster1; GameMap* myMap; // 背景条
Sprite* m_pBG;
// 血条。能量前景条
ProgressTimer* m_pHPBar;
ProgressTimer* m_pMPBar; ControlButton * m_pComboBtn;
Sprite* m_pComboPic; RenderTexture* render;
RenderTexture* renderResult; float velocity = 0.0f; // 跳起速度
float getVelocity(); // 获取跳跃的速度 bool m_bDirection; // 行走的方向
bool m_bRun; // 是否在跑
bool m_bJump; // 是否在跳 }; #endif
实现文件为:
/*!
* \class GameLayer
*
* \ingroup GroupName
*
* \brief
*
* TODO: long description
*
* \note
*
* \author SuooL
*
* \version 1.0
*
* \date 六月 2015
*
* Contact: hu1020935219@gmail.com
*
*/
#include "GameLayer.h"
#include "GameMap.h"
#include "Hero.h"
#include "Monster.h"
#include "PauseLayer.h"
#include "GateMapLayer.h"
#include "MonsterOne.h"
#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h" USING_NS_CC;
using namespace CocosDenshion;
using namespace cocos2d::extension; //引用cocos2d::extension命名空间 Scene* GameLayer::createScene()
{
Scene* scene = Scene::create();
GameLayer* layer = GameLayer::create();
scene->addChild(layer); return scene;
} bool GameLayer::init()
{
if (!Layer::init())
{
return false;
} if (getBoolFromXML(MUSIC_KEY))
{
float music = getFloatFromXML(MUSICVOL)*100.0f;
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying())
{
aduioEngine->pauseBackgroundMusic();
aduioEngine->playBackgroundMusic("Sound/gameBGM.wav", true);
}
else
aduioEngine->playBackgroundMusic("Sound/gameBGM.wav", true);
}
else
aduioEngine->pauseBackgroundMusic(); velocity = 10.0f;
m_bDirection = false;
m_bRun = false;
m_bJump = false; SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapBefore.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapRoad.plist"); String *bgName = String::createWithFormat("bgmap%d.png", m_iSelectGate);
String *midName = String::createWithFormat("MapMiddle%d.png", m_iSelectGate);
String *groundName = String::createWithFormat("MapGround%d.png", m_iSelectGate);
String *beforeName = String::createWithFormat("MapBefore%d.png", m_iSelectGate);
String *comoboName = String::createWithFormat("comboBtn%d.png", m_iSelectGate); auto bgPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(bgName->getCString()));
bgPic->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
this->addChild(bgPic, 0);
myMap = GameMap::create();
myMap->InitMap(midName->getCString(), groundName->getCString(), beforeName->getCString());
this->addChild(myMap, 1); // 界面控制键初始化
// 技能键
auto m_pFistBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("fist.png"));
auto m_pFistBtn = ControlButton::create(m_pFistBG);
m_pFistBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("fist.png"))->getContentSize()); auto m_pFootBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("foot.png"));
auto m_pFootBtn = ControlButton::create(m_pFootBG);
m_pFootBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("foot.png"))->getContentSize()); auto m_pJumpBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jump.png"));
auto m_pJumpBtn = ControlButton::create(m_pJumpBG);
m_pJumpBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jump.png"))->getContentSize()); auto m_pComboBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(comoboName->getCString()));
m_pComboBtn = ControlButton::create(m_pComboBG);
m_pComboBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(comoboName->getCString()))->getContentSize()); // 按键背景
auto m_pFistPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("quan.png"));
auto m_pFootPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jiao.png"));
auto m_pJumpPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tiao.png"));
m_pComboPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tiao.png")); auto m_pFistPicSize = m_pFistPic->getContentSize();
m_pFistBtn->setPosition(ccp(m_pFistPicSize.width / 2, m_pFistPicSize.height / 2));
m_pFistBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::fistAttack), Control::EventType::TOUCH_UP_INSIDE); auto m_pFootPicSize = m_pFootPic->getContentSize();
m_pFootBtn->setPosition(ccp(m_pFootPicSize.width / 2, m_pFootPicSize.height / 2));
m_pFootBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::footAttack), Control::EventType::TOUCH_UP_INSIDE); auto m_pJumpPicSize = m_pJumpPic->getContentSize();
m_pJumpBtn->setPosition(ccp(m_pJumpPicSize.width / 2.0 - 1.5, m_pJumpPicSize.height / 2));
m_pJumpBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::jump), Control::EventType::TOUCH_UP_INSIDE); auto m_pComboPicSize = m_pComboPic->getContentSize();
m_pComboBtn->setPosition(ccp(m_pComboPicSize.width / 2 - 1.5, m_pComboPicSize.height / 2));
m_pComboBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::comboAttack), Control::EventType::TOUCH_UP_INSIDE); m_pFistPic->addChild(m_pFistBtn, 1);
m_pFootPic->addChild(m_pFootBtn, 1);
m_pJumpPic->addChild(m_pJumpBtn, 1);
m_pComboPic->addChild(m_pComboBtn, 1); m_pFistPic->setPosition(WINSIZE.width - 230, 76);
m_pFootPic->setPosition(WINSIZE.width - 73, 76);
m_pJumpPic->setPosition(WINSIZE.width - 60, 220);
m_pComboPic->setPosition(WINSIZE.width - 387, 76); m_pComboPic->setVisible(false); this->addChild(m_pFistPic, 1);
this->addChild(m_pFootPic, 1);
this->addChild(m_pJumpPic, 1);
this->addChild(m_pComboPic, 1); // 行走控制键。暂停键
auto puaseGameItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseSelected.png")),
CC_CALLBACK_1(GameLayer::gamePause, this)); // Pause auto backwardBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionNormal.png"));
auto backwardSelBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionSelected.png"));
auto backwardBtn = ControlButton::create(backwardBG);
backwardBtn->setBackgroundSpriteForState(backwardSelBG, Control::State::HIGH_LIGHTED);
backwardBtn->setZoomOnTouchDown(false);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::TOUCH_DOWN);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::TOUCH_UP_INSIDE);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::DRAG_OUTSIDE);
backwardBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionNormal.png"))->getContentSize()); auto forwardBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForNor.png"));
auto forwardSelBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForSel.png"));
auto forwardBtn = ControlButton::create(forwardBG);
forwardBtn->setBackgroundSpriteForState(forwardSelBG, Control::State::HIGH_LIGHTED);
forwardBtn->setZoomOnTouchDown(false);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::TOUCH_DOWN);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::TOUCH_UP_INSIDE);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::DRAG_OUTSIDE);
forwardBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForNor.png"))->getContentSize()); puaseGameItem->setPosition(WINSIZE.width - 50, WINSIZE.height - 48);
backwardBtn->setPosition(117, 70);
forwardBtn->setPosition(304, 70); auto menuWalk = Menu::create(puaseGameItem, NULL);
menuWalk->setPosition(Point::ZERO);
this->addChild(backwardBtn, 1);
this->addChild(forwardBtn, 1);
this->addChild(menuWalk, 1); // 状态条
m_pBG = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("barGround.png")); m_pHPBar = ProgressTimer::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("HPBar.png")));
m_pHPBar->setType(ProgressTimer::Type::BAR);
m_pHPBar->setMidpoint(ccp(0, 0.5));
m_pHPBar->setBarChangeRate(ccp(1, 0));
m_pHPBar->setPercentage(100); m_pMPBar = ProgressTimer::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("MPBar.png")));
m_pMPBar->setType(ProgressTimer::Type::BAR);
m_pMPBar->setMidpoint(ccp(0, 0.5));
m_pMPBar->setBarChangeRate(ccp(1, 0));
m_pMPBar->setPercentage(0); m_pHPBar->setPosition(240, 45);
m_pMPBar->setPosition(226, 30); m_pBG->addChild(m_pHPBar);
m_pBG->addChild(m_pMPBar); m_pBG->setPosition(260, WINSIZE.height - 60); this->addChild(m_pBG, 1); // 英雄
m_pHero = Hero::create();
m_pHero->InitHeroSprite("idle.png", 1);
m_pHero->setPosition(100, 360);
this->addChild(m_pHero, 3); MonsterOne *monster = MonsterOne::createWithMapAndHero(myMap, m_pHero); this->scheduleUpdate();
return true;
} // 拳击
void GameLayer::fistAttack(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsRunning || m_pHero->IsAttack || m_pHero->IsHurt || m_pHero->m_bIsJumping)
{
return;
}
PLAYEFFECT;
m_pHero->AttackAnimation("fist", 0.1f, m_bDirection);
} // 腿击
void GameLayer::footAttack(Ref* psender, Control::EventType type)
{
if (m_pHero->IsRunning || m_pHero->IsAttack || m_pHero->IsHurt || m_pHero->m_bIsJumping)
{
return;
}
PLAYEFFECT;
m_pHero->AttackAnimation("leg", 0.1f, m_bDirection);
} //
void GameLayer::jump(Ref* pSender, Control::EventType type)
{ if (m_pHero->IsRunning || m_pHero->IsAttack || m_pHero->IsHurt || m_bJump)
{
return;
} if (getBoolFromXML(SOUND_KEY))
{
aduioEngine->setEffectsVolume(getFloatFromXML(SOUNDVOL));
aduioEngine->playEffect("Sound/Jump.wav");
} m_bJump = true;
} void GameLayer::comboAttack(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsAttack || m_pHero->m_bIsJumping == true || m_pHero->m_bCanCrazy)
{
return;
}
if (getBoolFromXML(SOUND_KEY))
{
aduioEngine->setEffectsVolume(getFloatFromXML(SOUNDVOL));
aduioEngine->playEffect("Sound/combo.wav");
}
m_pHero->m_bCanCrazy = true;
switch (m_iSelectGate)
{
case 1:
m_pHero->AttackAnimation("combo", 0.1, m_bDirection);
break;
case 2:
m_pHero->AttackAnimation("bakandao", 0.1, m_bDirection);
break;
case 3:
m_pHero->AttackAnimation("gun", 0.1, m_bDirection);
break;
default:
break;
}
} void GameLayer::gamePause(Ref* pSender)
{
//能够直接使用pause方法暂停当前的场景,可是这样做有一个bug,就是不能够屏蔽触摸事件,所以採用截图的方法
//Director::getInstance()->pause(); /*截取当前场景的图片而且保存*/ auto size = Director::getInstance()->getWinSize();
//RenderTexture是一个纹理渲染类,我们须要把要渲染的当前场景放进去,这是初始化它的大小
render = RenderTexture::create(size.width, size.height);
//開始获取内容
render->begin();
//是用节点的visit方法增加到渲染中
Director::getInstance()->getRunningScene()->visit();
//结束
render->end();
render->retain(); //3.0 截屏须要在截完屏的下一帧才干处理RenderTexture,这点要注意
auto _schedule = this->getScheduler();
auto replaceScene = [&](float tm)
{
//最后切换场景
Director::getInstance()->pushScene(PauseLayer::createScene(render));
};
_schedule->schedule(replaceScene, this, 0.0f, 0, 0.0f, false, "screenshot");
} void GameLayer::backward(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsAttack && m_pHero->m_bIsJumping == true)
{
return;
}
switch (type)
{
case cocos2d::extension::Control::EventType::TOUCH_DOWN:
m_bRun = true;
m_bDirection = true;
break;
case cocos2d::extension::Control::EventType::DRAG_INSIDE:
break;
case cocos2d::extension::Control::EventType::DRAG_OUTSIDE:
m_bRun = false;
m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::DRAG_ENTER:
break;
case cocos2d::extension::Control::EventType::DRAG_EXIT:
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_INSIDE:
m_bRun = false;
m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_OUTSIDE:
break;
case cocos2d::extension::Control::EventType::TOUCH_CANCEL:
break;
case cocos2d::extension::Control::EventType::VALUE_CHANGED:
break;
default:
break;
}
} void GameLayer::forward(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsAttack && m_pHero->m_bIsJumping == true)
{
return;
}
switch (type)
{
case cocos2d::extension::Control::EventType::TOUCH_DOWN:
m_bRun = true;
m_bDirection = false;
break;
case cocos2d::extension::Control::EventType::DRAG_INSIDE:
break;
case cocos2d::extension::Control::EventType::DRAG_OUTSIDE:
m_bRun = false;
m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::DRAG_ENTER:
break;
case cocos2d::extension::Control::EventType::DRAG_EXIT:
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_INSIDE:
m_bRun = false;
m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_OUTSIDE:
break;
case cocos2d::extension::Control::EventType::TOUCH_CANCEL:
break;
case cocos2d::extension::Control::EventType::VALUE_CHANGED:
break;
default:
break;
}
} void GameLayer::gameOver(float delta)
{
// 对声音的处理
if (getBoolFromXML(MUSIC_KEY))
{
float music = getFloatFromXML(MUSICVOL)*100.0f;
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying())
{
aduioEngine->pauseBackgroundMusic();
aduioEngine->playBackgroundMusic("Sound/failure.wav", true);
}
else
aduioEngine->playBackgroundMusic("Sound/failure.wav", true);
}
else
aduioEngine->pauseBackgroundMusic();
// 弹出游戏失败的界面
auto bgSprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("heiping.png"));
bgSprite->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
this->addChild(bgSprite, 5);
auto bgTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bgTitle.png"));
bgTitle->setPosition(WINSIZE.width / 2 + 23, WINSIZE.height / 2 + 17);
auto faliureTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("faliure.png"));
faliureTitle->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 + 227);
auto energyTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tili.png"));
energyTitle->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 23);
auto tips = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tipsNext.png"));
tips->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 227); auto m_pEnergyLabel = LabelTTF::create("- 1", "", 45);
m_pEnergyLabel->setColor(ccc3(0, 255, 255));
m_pEnergyLabel->setPosition(300, 60); bgSprite->addChild(bgTitle);
bgSprite->addChild(faliureTitle);
bgSprite->addChild(energyTitle);
bgSprite->addChild(tips); // 获取事件分发器
auto dispatcher = Director::getInstance()->getEventDispatcher();
// 触摸监听器
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [](Touch* touch, Event* event){return true; };
listener->onTouchMoved = [](Touch* touch, Event* event){};
listener->onTouchEnded = [](Touch* touch, Event* event){
Director::getInstance()->replaceScene(GateMapLayer::createScene());
};
listener->setSwallowTouches(true);
dispatcher->addEventListenerWithSceneGraphPriority(listener, bgSprite);
} void GameLayer::gameVictory(float delta)
{
// 对声音的处理
if (getBoolFromXML(MUSIC_KEY))
{
float music = getFloatFromXML(MUSICVOL)*100.0f;
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying())
{
aduioEngine->pauseBackgroundMusic();
aduioEngine->playBackgroundMusic("Sound/victory.wav", true);
}
else
aduioEngine->playBackgroundMusic("Sound/victory.wav", true);
}
else
aduioEngine->pauseBackgroundMusic(); if (m_iSelectGate == 1)
{
setBoolToXML(GATEONE, true);
}
else if (m_iSelectGate == 2)
{
setBoolToXML(GATETWO, true);
}
else
setBoolToXML(GATETHREE, true); // 弹出游戏胜利的界面
auto bgSprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("heiping.png"));
bgSprite->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
this->addChild(bgSprite, 5);
auto bgTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bgTitle.png"));
bgTitle->setPosition(WINSIZE.width / 2 + 23, WINSIZE.height / 2 + 17);
auto victoryTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("victory.png"));
victoryTitle->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 + 227);
auto energyTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tili.png"));
energyTitle->setPosition(WINSIZE.width / 2 + 116, WINSIZE.height / 2 - 23);
auto moneyTitle = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jinbi.png"));
moneyTitle->setPosition(WINSIZE.width / 2 - 275, WINSIZE.height / 2 - 27);
auto tips = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tipsNext.png"));
tips->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 227);
bgSprite->addChild(bgTitle);
bgSprite->addChild(victoryTitle);
bgSprite->addChild(energyTitle);
bgSprite->addChild(moneyTitle);
bgSprite->addChild(tips); // 获取事件分发器
auto dispatcher = Director::getInstance()->getEventDispatcher();
// 触摸监听器
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [](Touch* touch, Event* event){return true; };
listener->onTouchMoved = [](Touch* touch, Event* event){};
listener->onTouchEnded = [](Touch* touch, Event* event){
Director::getInstance()->replaceScene(GateMapLayer::createScene());
};
listener->setSwallowTouches(true);
dispatcher->addEventListenerWithSceneGraphPriority(listener, bgSprite);
} bool GameLayer::isAttackMonster(Hero * hero, Monster* monster)
{
bool hero_dire = hero->HeroDirecton;
bool monster_dire = monster->MonsterDirecton;
float hero_x = hero->getPositionX();
float monster_x = monster->getPositionX() + myMap->getPositionX();
if (hero_dire)
{
if (monster_x <= hero_x)
{
return true;
}
}
else
{
if (monster_x >= hero_x)
{
return true;
}
} return false;
} float GameLayer::getVelocity()
{
velocity = velocity - 0.3f;
return velocity;
} void GameLayer::update(float delta)
{
// 人物跳起
if (m_bJump)
{
getVelocity(); if (velocity >= 0.1) // 速度不为0
{
m_pHero->JumpUpAnimation("jumpup", 0.1f, m_bDirection);
if (m_bDirection == false)
{
if (m_pHero->getPositionX() <= WINSIZE.width - 8)//不让精灵超出右边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero)) //精灵没到达窗体中间位置或者地图已经移动到边缘了,精灵才干够移动。否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x + m_pHero->m_iSpeed, m_pHero->getPosition().y + velocity)); //向右走
else
{
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
//以下是移动地图
myMap->MoveMap(m_pHero);
}
else
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
else
{
if (m_pHero->getPositionX() >= 8)//不让精灵超出左边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero))//精灵没到达窗体中间位置或者地图已经移动到边缘了,精灵才干够移动,否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x - m_pHero->m_iSpeed, m_pHero->getPosition().y + velocity)); //向左走
else
{
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
//以下是移动地图
myMap->MoveMap(m_pHero);
}
else
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
} }
else
{
m_pHero->JumpDownAnimation("jumpdown", 0.1f, m_bDirection);
if (m_bDirection == false)
{
if (m_pHero->getPositionX() <= WINSIZE.width - 8)//不让精灵超出右边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero))//精灵没到达窗体中间位置或者地图已经移动到边缘了,精灵才干够移动。否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x + m_pHero->m_iSpeed, m_pHero->getPosition().y + velocity)); //向右走
else
{
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
//以下是移动地图
myMap->MoveMap(m_pHero);
}
else
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
else
{
if (m_pHero->getPositionX() >= 8)//不让精灵超出左边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero))//精灵没到达窗体中间位置或者地图已经移动到边缘了。精灵才干够移动。否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x - m_pHero->m_iSpeed, m_pHero->getPosition().y + velocity)); //向左走
else
{
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
//以下是移动地图
myMap->MoveMap(m_pHero);
}
else
m_pHero->setPosition(ccp(m_pHero->getPosition().x, m_pHero->getPosition().y + velocity)); //向左走
}
} if (m_pHero->getPositionY() <= 359)
{
m_pHero->JumpEnd();
m_pHero->setPosition(ccp(m_pHero->getPosition().x + 3, 360));
velocity = 10.0f;
m_bJump = false;
}
} // 人物移动
if (m_bRun && m_bDirection == false && m_pHero->IsHurt == false && m_pHero->IsAttack == false && m_pHero->m_bIsJumping == false)
{
m_pHero->SetAnimation("run", 0.07f, m_bDirection);
if (m_pHero->getPositionX() <= WINSIZE.width - 8)//不让精灵超出右边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero))//精灵没到达窗体中间位置或者地图已经移动到边缘了。精灵才干够移动,否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x + m_pHero->m_iSpeed, m_pHero->getPosition().y)); //向右走
//以下是移动地图
myMap->MoveMap(m_pHero);
}
}
else if (m_bRun && m_bDirection == true && m_pHero->IsHurt == false && m_pHero->m_bIsJumping == false)
{
m_pHero->SetAnimation("run", 0.07f, m_bDirection);
if (m_pHero->getPositionX() >= 8)//不让精灵超出左边,8能够改成你喜欢的
{
if (!m_pHero->JudgePosition(WINSIZE) || myMap->JudgeMap(m_pHero))//精灵没到达窗体中间位置或者地图已经移动到边缘了,精灵才干够移动,否则仅仅播放动画
m_pHero->setPosition(ccp(m_pHero->getPosition().x - m_pHero->m_iSpeed, m_pHero->getPosition().y)); //向右走
//以下是移动地图
myMap->MoveMap(m_pHero);
}
} // 主角和怪物攻击碰撞检測
if (m_pHero->IsAttack)
{
for (auto monster : monsterShowList)
{
// 怪物没死
if (monster->Isdead == false && isAttackMonster(m_pHero, monster) && m_pHero->m_bIsJumping == false)
{
// 得到两点x的距离, 记得怪物的坐标要加上地图的
float x = m_pHero->getPositionX() - (monster->getPositionX() + myMap->getPositionX()); //先计算怪物和英雄的距离
auto dis = fabs(x);
if (dis <= 150)
{
if (monster->m_iType == 1)
{
monster->HurtAnimation("monsterHurt", monster->MonsterDirecton, 0.2f, 1);
}
else if (monster->m_iType == 2)
{
monster->HurtAnimation("lionHurt", monster->MonsterDirecton, 0.2f, 1);
}
else
{
monster->HurtAnimation("stoneHurt", monster->MonsterDirecton, 0.2f, 1);
}
}
// if (this->isRectCollision(CCRectMake(m_pHero->getPositionX(), m_pHero->getPositionY(), m_pHero->GetSprite()->getContentSize().width-30, m_pHero->GetSprite()->getContentSize().height-20),
// CCRectMake(monster->getPositionX(), monster->getPositionY(), monster->GetSprite()->getContentSize().width - 30, monster->GetSprite()->getContentSize().height - 20)))
// {
// monster->HurtAnimation("monsterHurt", monster->MonsterDirecton, 0.2f, 1);
// }
}
}
} for (auto monster : monsterShowList)
{
if (!monster->Isdead)
{
if (monster->IsAttack && m_pHero->IsDead == false && m_pHero->m_bIsJumping == false)
{
// 得到两点x的距离, 记得怪物的坐标要加上地图的
float x = m_pHero->getPositionX() - (monster->getPositionX() + myMap->getPositionX()); //先计算怪物和英雄的距离
auto dis = fabs(x);
if (dis <= 130)
{
m_pHero->HurtByMonsterAnimation("hurt", 0.2f, m_bDirection);
m_pHPBar->setPercentage(m_pHero->percentage);
}
}
}
} m_pMPBar->setPercentage(m_pHero->m_iCurrentMp);
if (m_pMPBar->getPercentage() >= 100)
{
m_pComboPic->setVisible(true);
}
else
{
m_pComboPic->setVisible(false);
} // 主角和怪物攻击碰撞检測
if (m_pHero->IsAttack && m_pHero->m_bCanCrazy)
{
for (auto monster : monsterShowList)
{
// 怪物没死
if (monster->Isdead == false && isAttackMonster(m_pHero, monster) && m_pHero->m_bIsJumping == false)
{
// 得到两点x的距离, 记得怪物的坐标要加上地图的
float x = m_pHero->getPositionX() - (monster->getPositionX() + myMap->getPositionX()); //先计算怪物和英雄的距离
auto dis = fabs(x);
if (dis <= 350)
{
monster->HurtAnimation("monsterHurt", monster->MonsterDirecton, 0.2f, 1);
}
// if (this->isRectCollision(CCRectMake(m_pHero->getPositionX(), m_pHero->getPositionY(), m_pHero->GetSprite()->getContentSize().width-30, m_pHero->GetSprite()->getContentSize().height-20),
// CCRectMake(monster->getPositionX(), monster->getPositionY(), monster->GetSprite()->getContentSize().width - 30, monster->GetSprite()->getContentSize().height - 20)))
// {
// monster->HurtAnimation("monsterHurt", monster->MonsterDirecton, 0.2f, 1);
// }
}
}
} // 游戏结束判定
if (m_pHero->IsDead)
{
// 游戏结束
this->scheduleOnce(schedule_selector(GameLayer::gameOver), 1.0f);
this->unscheduleUpdate();
}
// 怪物全死
if (m_bFlag3 == false)
{
bool noMonster = true;
for (auto monster : monsterShowList)
{
if (!monster->Isdead)
{
noMonster = false;
}
}
if (noMonster)
{
this->scheduleOnce(schedule_selector(GameLayer::gameVictory), 2.0f);
this->unscheduleUpdate();
}
}
}
关于暂停场景的实现例如以下,由于暂停要实现一个动态的开关效果,并且背景是游戏暂停的场景。所以做了一个截图,传递给这个场景,代码实现例如以下:
/*!
* \file PauseLayer.h
*
* \author SuooL
* \date 六月 2015
*
* 暂停界面
*/ #ifndef __PauseLayer__H__
#define __PauseLayer__H__
#include "cocos2d.h"
#include "extensions/cocos-ext.h" USING_NS_CC;
using namespace cocos2d::extension; class PauseLayer : public Layer {
public:
static Scene* createScene(RenderTexture* rt);
virtual bool init();
CREATE_FUNC(PauseLayer); Sprite* spriteOn;
Sprite* spriteDown; void musicSet(Ref* pSender); private: }; #endif
实现文件为:
/*!
* \file PauseLayer.cpp
* \date 2015/04/08 15:30
*
* \author SuooL
* Contact: 1020935219@qq.com
*
* \brief 暂停界面
*
* \version 1.0
*
* TODO: long description
*
* \note
*/
#include "PauseLayer.h"
#include "GlobalDefine.h"
#include "GlobalData.h"
#include "GameLayer.h"
#include "StartLayer.h"
#include "cocos2d.h"
#include "extensions/cocos-ext.h" USING_NS_CC;
using namespace cocos2d::extension; Scene* PauseLayer::createScene(RenderTexture* rt)
{
Scene* scene = Scene::create();
PauseLayer* layer = PauseLayer::create(); auto sprite = Sprite::createWithTexture(rt->getSprite()->getTexture());
sprite->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
sprite->setFlippedY(true);
// sprite->setColor(cocos2d::ccGRAY);
scene->addChild(sprite, 0); scene->addChild(layer); return scene;
} bool PauseLayer::init()
{
if (!Layer::init())
{
return false;
} auto size = Director::getInstance()->getWinSize(); // 背景黑色的图片
spriteOn = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseBG1.png"));
spriteDown = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseBG2.png"));
spriteOn->setPosition(size.width / 2, size.height + spriteOn->getContentSize().height / 2);
spriteDown->setPosition(size.width / 2, - (spriteDown->getContentSize().height / 2));
this->addChild(spriteOn);
this->addChild(spriteDown); /*
继续游戏button: X:630.5 Y349.0
声音按键:X:190.0 Y294.0
重置键button:X346.0 Y:294.0
返回关卡界面键button:X890.0 Y:294.0
下一关键button:X1053.0 Y:294.0
*/
// 继续游戏button
auto resumeItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("playNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("playSelected.png")),
[&](Ref * ref){
PLAYEFFECT;
//弹出保存的场景
auto moveOn = MoveBy::create(0.5f, Point(0, (spriteOn->getContentSize().height)));
auto moveDown = MoveBy::create(0.5f, Point(0, -spriteDown->getContentSize().height));
CallFunc* replace = CallFunc::create([](){Director::getInstance()->popScene();});
Action* resume = Sequence::create(moveOn, replace, NULL);
spriteDown->runAction(moveDown);
spriteOn->runAction(resume);
});
resumeItem->setPosition(spriteOn->getContentSize().width / 2-5, 110.0f); // 返回游戏主界面
auto startItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("backNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("backSelected.png")),
[](Ref * ref){
PLAYEFFECT;
//弹出保存的场景
Director::getInstance()->replaceScene(StartLayer::createScene());});
startItem->setPosition(890.0f, 180.0f); // 又一次開始游戏
auto againItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("againNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("againSelected.png")),
[](Ref * ref){
PLAYEFFECT;
//弹出保存的场景
Director::getInstance()->replaceScene(GameLayer::createScene());});
againItem->setPosition(346.0f, 180.0f);
// 下一关
auto nextItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("nextNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("nextSelected.png")),
[](Ref * ref){
PLAYEFFECT;
//弹出保存的场景
if (m_iSelectGate++ < 3)
{
Director::getInstance()->replaceScene(GameLayer::createScene());
}
});
nextItem->setPosition(1053.0f, 180.0f); // 声音设置button
auto musicOn = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("musicOn.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("musicOff.png")));
auto musicOff = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("musicOff.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("musicSelected.png")));
auto musciToggle = MenuItemToggle::createWithTarget(this, menu_selector(PauseLayer::musicSet), musicOn, musicOff, NULL);
musciToggle->setPosition(190.0f, 180.0f); auto menu = Menu::create(resumeItem, startItem, againItem, nextItem,musciToggle, NULL);
menu->setPosition(Point::ZERO);
spriteOn->addChild(menu); auto moveDown = MoveBy::create(0.6f, Point(0, - (spriteOn->getContentSize().height)));
auto moveUp = MoveBy::create(0.6f, Point(0, spriteDown->getContentSize().height));
spriteOn->runAction(moveDown);
spriteDown->runAction(moveUp); } void PauseLayer::musicSet(Ref* pSender)
{
PLAYEFFECT;
auto musicTemp = (MenuItemToggle*)pSender;
if (getBoolFromXML(SOUND_KEY))
{
aduioEngine->setEffectsVolume(getFloatFromXML(SOUNDVOL));
aduioEngine->playEffect("");
}
if (musicTemp->getSelectedIndex() == 1)
{
SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
else
{
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
}
代码的凝视已经很具体了。
假设您有不明确的地方能够留言或者邮箱我:1020935219@qq.com
整个project的源代码已经开源,地址是:https://github.com/SuooL/KungfuBoy
下一课将会说明下打包APK和项目打包过程及打包后会出现的一些问题及其解决办法。
【Cocos游戏实战】功夫小子第七课之游戏主功能场景逻辑功能和暂停功能场景的分析和实现的更多相关文章
- 【Cocos游戏实战】功夫小子第八课之游戏打包和相关问题说明
至此,功夫小子系列的Cocos2d-x的实战文章就结束了. 源代码地址: https://github.com/SuooL/KungfuBoy 如须要资源请邮件我 1020935219@qq.com ...
- 【Cocos游戏实战】功夫小子第五课之帮助场景和选关功能的实现
功夫小子之帮助场景和选关功能的实现 转载请注明出处:http://blog.csdn.net/suool/article/details/46661231 本节课的视频教程地址是: hmsr=teac ...
- 【C语言探索之旅】 第二部分第七课:文件读写
内容简介 1.课程大纲 2.第二部分第七课: 文件读写 3.第二部分第八课预告: 动态分配 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏 ...
- 【C语言探索之旅】 第一部分第七课:循环语句
内容简介 1.课程大纲 2.第一部分第七课: 循环语句 3.第一部分第八课预告: 第一个C语言小游戏 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编 ...
- Java 测试驱动开发--“井字游戏” 游戏实战
TDD 介绍 TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论.TDD的原理是在开发功能代码之前,先编写单元测试用 ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- Kali Linux Web 渗透测试视频教程— 第七课 OpenVas
Kali Linux Web 渗透测试视频教程— 第七课 OpenVas 文/玄魂 视频教程地址:http://edu.51cto.com/course/course_id-1887.html 目录 ...
- Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-1
学习目标 一.进一步学习Swift的游戏制作 二.掌握SKNode,SKSpriteNode的运用 三.了解SpriteKit的物理系统 四.掌握动作(SKAction)的运用 在这一章,我们要通过制 ...
- Swift游戏实战-跑酷熊猫 14 熊猫打滚
这节内容我们来实现熊猫打滚.思路是这样的,当熊猫起跳时记录他的Y坐标,落到平台上的时候再记录它的Y坐标.两个坐标之间的差要是大于一定数值就判断它从高处落下要进行打滚缓冲.至此跑酷熊猫已经像一个游戏的样 ...
随机推荐
- Problem F: 多少个最大值?
Description 输入若干个int类型的整数,求它们的最大值及其个数. Input 输入 若干个int类型的整数,至文件尾为止. Output 输出只有一行:There are # maximu ...
- Fiddler系列教程3:使用Fiddler录制Jmeter性能测试脚本
今天继续给大家带来Fiddler工具的教程3:使用Fiddler录制Jmter性能测试脚本. 我们知道Jmeter本身可以录制脚本,也可以通过BadBoy,BlazeMeter等工具进行录制,其实Fi ...
- linux数据库备份脚本
数据库备份1.创建个备份存储目录mkdir /root/backup/2.以下内容写到dbbackup.sh(注意,使用VIM 或者VI命令新建文件,不要在WINDOWS下新建,否则可能提示 No s ...
- 03.javabean
一.javabean简介 1, 作用:一个可重用组件,在jsp开发中可减少重复代码,使HTML与JAVA代码分离便于日后维护. 2, javabean类要求: 所有类必须放在包中,且为public ...
- Unity 游戏框架搭建 (二十) 更安全的对象池
上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...
- 文本域、bootstrap-table显示以及MySQL三者间的换行符问题
首先,今天在做项目的时候遇到的一个问题,如何实现文本输入换行以及在前台Bootstrap-table中显示也能够换行. 也许你马上就会想到说,用富文本编辑器,然而我们需要实现的只是文本输入以及换行功能 ...
- Vue浅谈
谈Vue 最近在学习Vue相关的知识点并且也做一些练手,就在学习过程中出现的各种坑爹的地方做一个总结!之后再遇到也不会抓瞎. 1.Vue工程的安装 (1)首先先安装node.js这是Vue的运行基础. ...
- 结合程序崩溃后的core文件分析bug
引言 在<I/O的效率比较>中,我们在修改图1程序的BUF_SIZE为8388608时,运行程序出现崩溃,如下图1: 图1. 段错误 一般而言,导致程序段 ...
- WebService学习总结
因为最近开发的项目需求中涉及到了webservice,正好对这块知识以前学过但是又忘记了,于是想着从新学习下,整理一个笔记,便于后面的复习.于是有了本文,下面开始介绍webservice. 一.简介 ...
- 用JavaScript实现表格编辑器
实现效果: htm l代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...