cocos2d-x 提升篇 (17) 簡單的桌上足球遊戲
這個例子改編來自Cocos2d-x by Example.
相當於一個簡單的桌上足球遊戲,可以通過觸控的方式碰撞紅色的球,進入對方的球門就可以加一分。
#ifndef _APP_DELEGATE_H_
#define _APP_DELEGATE_H_
#include "cocos2d.h"
/**
@brief The cocos2d Application.
Private inheritance here hides part of interface from Director.
*/
class AppDelegate : private cocos2d::Application
{
public:
AppDelegate();
virtual ~AppDelegate();
virtual void initGLContextAttrs();
/**
@brief Implement Director and Scene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
virtual bool applicationDidFinishLaunching();
/**
@brief Called when the application moves to the background
@param the pointer of the application
*/
virtual void applicationDidEnterBackground();
/**
@brief Called when the application reenters the foreground
@param the pointer of the application
*/
virtual void applicationWillEnterForeground();
};
#endif // _APP_DELEGATE_H_
#include "AppDelegate.h"
#include "HelloWorldScene.h"
#include "GameLayer.h"
#include "TestLayer.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
using namespace cocos2d;
USING_NS_CC;
// static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320);
static cocos2d::Size designResolutionSize = cocos2d::Size(720, 1280);
static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 320);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536);
AppDelegate::AppDelegate()
{
}
AppDelegate::~AppDelegate()
{
}
// if you want a different context, modify the value of glContextAttrs
// it will affect all platforms
void AppDelegate::initGLContextAttrs()
{
// set OpenGL context attributes: red,green,blue,alpha,depth,stencil
GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
GLView::setGLContextAttrs(glContextAttrs);
}
// if you want to use the package manager to install more packages,
// don't modify or remove this function
static int register_all_packages()
{
return 0; //flag for packages manager
}
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
glview = GLViewImpl::createWithRect("GameDemo", cocos2d::Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
glview = GLViewImpl::create("GameDemo");
#endif
director->setOpenGLView(glview);
}
// turn on display FPS
director->setDisplayStats(false);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0f / 60);
glview->setFrameSize(720, 1280);
// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::EXACT_FIT);
/*
auto frameSize = glview->getFrameSize();
// if the frame's height is larger than the height of medium size.
if (frameSize.height > mediumResolutionSize.height)
{
director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is larger than the height of small size.
else if (frameSize.height > smallResolutionSize.height)
{
director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium size.
else
{
director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
}
*/
register_all_packages();
// preload sound effects
// SimpleAudioEngine::sharedEngine()->preloadEffect("standard/hit.wav");
// SimpleAudioEngine::sharedEngine()->preloadEffect("standard/score.wav");
auto fileUtils = FileUtils::getInstance();
std::vector<std::string> searchPaths;
searchPaths.push_back("standard");
fileUtils->setSearchPaths(searchPaths);
auto audioEngine = SimpleAudioEngine::getInstance();
audioEngine->preloadEffect(fileUtils->fullPathForFilename("hit.wav").c_str());
audioEngine->preloadEffect(fileUtils->fullPathForFilename("score.wav").c_str());
audioEngine->setBackgroundMusicVolume(0.5f);
audioEngine->setEffectsVolume(0.5f);
// create a scene. it's an autorelease object
auto scene = HelloWorld::createScene();
// auto scene = GameLayer::createScene();
// auto scene = TestLayer::createScene();
// run
director->runWithScene(scene);
return true;
}
// This function will be called when the app is inactive. Note, when receiving a phone call it is invoked.
void AppDelegate::applicationDidEnterBackground() {
Director::getInstance()->stopAnimation();
// if you use SimpleAudioEngine, it must be paused
// SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
Director::getInstance()->startAnimation();
// if you use SimpleAudioEngine, it must resume here
// SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
#include "GameLayer.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
bool GameLayer::init()
{
if (!Layer::init())
return false;
_players = Vector<GameSprite*>(2);
_player1Score = 0;
_player2Score = 0;
_screenSize = Director::getInstance()->getWinSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto court = Sprite::create("court.png");
court->setPosition(Vec2(_screenSize.width * 0.5, _screenSize.height * 0.5));
this->addChild(court);
_player1 = GameSprite::gameSpriteWithFile("mallet.png");
_player1->setPosition(Vec2(_screenSize.width/2, _player1->radius()*2));
_players.pushBack(_player1);
this->addChild(_player1);
_player2 = GameSprite::gameSpriteWithFile("mallet.png");
_player2->setPosition(Vec2(_screenSize.width/2, _screenSize.height - _player1->radius()*2));
_players.pushBack(_player2);;
this->addChild(_player2);
_ball = GameSprite::gameSpriteWithFile("puck.png");
_ball->setPosition(Vec2(_screenSize.width/2, _screenSize.height/2 - _ball->radius()*2));
this->addChild(_ball);
_player1ScoreLabel = Label::createWithTTF("0", "fonts/arial.ttf", 40);
_player1ScoreLabel->setPosition(Vec2(_screenSize.width/4*3, _screenSize.height/2 - 50));
_player1ScoreLabel->setAnchorPoint(Vec2(0.5, 0.5));
_player1ScoreLabel->setRotation(90);
this->addChild(_player1ScoreLabel);
_player2ScoreLabel = Label::createWithTTF("0", "fonts/arial.ttf", 40);
_player2ScoreLabel->setPosition(Vec2(_screenSize.width/4*3, _screenSize.height/2 + 50));
_player2ScoreLabel->setAnchorPoint(Vec2(0.5, 0.5));
_player2ScoreLabel->setRotation(90);
this->addChild(_player2ScoreLabel);
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan =
CC_CALLBACK_2(GameLayer::onTouchesBegan,this);
listener->onTouchesMoved =
CC_CALLBACK_2(GameLayer::onTouchesMoved, this);
listener->onTouchesEnded =
CC_CALLBACK_2(GameLayer::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
// create main loop
this->scheduleUpdate();
return true;
}
Scene *GameLayer::createScene()
{
Scene* scene = Scene::create();
GameLayer* layer = GameLayer::create();
scene->addChild(layer);
return scene;
}
void GameLayer::onTouchesBegan(const std::vector<Touch *> &touches, Event *event)
{
for (auto touch : touches) {
if (touch != nullptr) {
auto tap = touch->getLocation();
for (auto player : _players) {
if (player->boundingBox().containsPoint(tap)) {
player->setTouch(touch);
}
}
}
}
}
void GameLayer::onTouchesMoved(const std::vector<Touch *> &touches, Event *event)
{
for (auto touch : touches) {
if (touch != nullptr) {
auto tap = touch->getLocation();
for (auto player : _players) {
if (player->getTouch() != nullptr && player->getTouch() == touch) {
Point nextPosition = tap;
if (nextPosition.x < player->radius())
nextPosition.x = player->radius();
if (nextPosition.x > _screenSize.width - player->radius())
nextPosition.x = _screenSize.width - player->radius();
if (nextPosition.y < player->radius())
nextPosition.y = player->radius();
if (nextPosition.y > _screenSize.height - player->radius())
nextPosition.y = _screenSize.height - player->radius();
//keep player inside its court
if (player->getPositionY() < _screenSize.height* 0.5f) {
if (nextPosition.y > _screenSize.height* 0.5 -
player->radius()) {
nextPosition.y = _screenSize.height* 0.5 -
player->radius();
}
} else {
if (nextPosition.y < _screenSize.height* 0.5 +
player->radius()) {
nextPosition.y = _screenSize.height* 0.5 +
player->radius();
}
}
player->setNextPosition(nextPosition);
player->setVector(Vec2(tap.x - player->getPositionX(),
tap.y - player->getPositionY()));
}
}
}
}
}
void GameLayer::onTouchesEnded(const std::vector<Touch *> &touches, Event *event)
{
for (auto touch : touches) {
if (touch != nullptr) {
auto tap = touch->getLocation();
for (auto player : _players) {
if (player->getTouch() != nullptr && player->getTouch() == touch) {
//if touch ending belongs to this player, clear it
player->setTouch(nullptr);
player->setVector(Vec2(0,0));
}
}
}
}
}
void GameLayer::update(float dt)
{
CCPoint ballNextPosition = _ball->getNextPosition();
CCPoint ballVector = _ball->getVector();
ballVector = ccpMult(ballVector, 0.98f);
ballNextPosition.x += ballVector.x;
ballNextPosition.y += ballVector.y;
//test for puck and mallet collision
float squared_radii = pow(_player1->radius() + _ball->radius(), 2);
GameSprite * player;
CCPoint playerNextPosition;
CCPoint playerVector;
for (int p = 0; p < 2; p++) {
player = _players.at(p);
playerNextPosition = player->getNextPosition();
playerVector = player->getVector();
float diffx = ballNextPosition.x - player->getPositionX();
float diffy = ballNextPosition.y - player->getPositionY();
float distance1 = pow(diffx, 2) + pow(diffy, 2);
float distance2 = pow(_ball->getPositionX() - playerNextPosition.x, 2) + pow(_ball->getPositionY() - playerNextPosition.y, 2);
if (distance1 <= squared_radii || distance2 <= squared_radii) {
float mag_ball = pow(ballVector.x, 2) + pow(ballVector.y, 2);
float mag_player = pow (playerVector.x, 2) + pow (playerVector.y, 2);
float force = sqrt(mag_ball + mag_player);
float angle = atan2(diffy, diffx);
ballVector.x = force * cos(angle);
ballVector.y = (force * sin(angle));
ballNextPosition.x = playerNextPosition.x + (player->radius() + _ball->radius() + force) * cos(angle);
ballNextPosition.y = playerNextPosition.y + (player->radius() + _ball->radius() + force) * sin(angle);
SimpleAudioEngine::sharedEngine()->playEffect("hit.wav");
}
}
//check collision of ball and sides
if (ballNextPosition.x < _ball->radius()) {
ballNextPosition.x = _ball->radius();
ballVector.x *= -0.8f;
SimpleAudioEngine::sharedEngine()->playEffect("hit.wav");
}
if (ballNextPosition.x > _screenSize.width - _ball->radius()) {
ballNextPosition.x = _screenSize.width - _ball->radius();
ballVector.x *= -0.8f;
SimpleAudioEngine::sharedEngine()->playEffect("hit.wav");
}
//ball and top of the court
if (ballNextPosition.y > _screenSize.height - _ball->radius()) {
if (_ball->getPosition().x < _screenSize.width * 0.5f - GOAL_WIDTH * 0.5f ||
_ball->getPosition().x > _screenSize.width * 0.5f + GOAL_WIDTH * 0.5f) {
ballNextPosition.y = _screenSize.height - _ball->radius();
ballVector.y *= -0.8f;
SimpleAudioEngine::sharedEngine()->playEffect("hit.wav");
}
}
//ball and bottom of the court
if (ballNextPosition.y < _ball->radius() ) {
if (_ball->getPosition().x < _screenSize.width * 0.5f - GOAL_WIDTH * 0.5f ||
_ball->getPosition().x > _screenSize.width * 0.5f + GOAL_WIDTH * 0.5f) {
ballNextPosition.y = _ball->radius();
ballVector.y *= -0.8f;
SimpleAudioEngine::sharedEngine()->playEffect("hit.wav");
}
}
//finally, after all checks, update ball's vector and next position
_ball->setVector(ballVector);
_ball->setNextPosition(ballNextPosition);
//check for goals!
if (ballNextPosition.y < -_ball->radius() * 2) {
this->playerScore(2);
}
if (ballNextPosition.y > _screenSize.height + _ball->radius() * 2) {
this->playerScore(1);
}
//move pieces to next position
_player1->setPosition(_player1->getNextPosition());
_player2->setPosition(_player2->getNextPosition());
_ball->setPosition(_ball->getNextPosition());
}
void GameLayer::playerScore(int player)
{
SimpleAudioEngine::sharedEngine()->playEffect("score.wav");
_ball->setVector(CCPointZero);
char score_buffer[10];
//if player 1 scored...
if (player == 1) {
_player1Score++;
sprintf(score_buffer,"%i", _player1Score);
_player1ScoreLabel->setString(score_buffer);
//move ball to player 2 court
_ball->setNextPosition(ccp(_screenSize.width * 0.5, _screenSize.height * 0.5 + 2 * _ball->radius()));
//if player 2 scored...
} else {
_player2Score++;
sprintf(score_buffer,"%i", _player2Score);
_player2ScoreLabel->setString(score_buffer);
//move ball to player 1 court
_ball->setNextPosition(ccp(_screenSize.width * 0.5, _screenSize.height * 0.5 - 2 * _ball->radius()));
}
//move players to original position
_player1->setPosition(ccp(_screenSize.width * 0.5, _player1->radius() * 2));
_player2->setPosition(ccp(_screenSize.width * 0.5, _screenSize.height - _player1->radius() * 2));
//clear current touches
_player1->setTouch(NULL);
_player2->setTouch(NULL);
}
GameLayer::GameLayer()
{
}
GameLayer::~GameLayer()
{
}
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "GameLayer.h"
#include "RocketThrough/RocketThrough.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto _screenSize = Director::getInstance()->getWinSize();
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
// create menuMenu, which game to choose
auto menuItem1 = MenuItemFont::create("Air Hockey");
menuItem1->setFontSizeObj(60);
menuItem1->setPosition(Vec2(_screenSize.width/2, _screenSize.height/5*4));
menuItem1->setCallback([&](Ref *sender){
auto director = Director::getInstance();
director->replaceScene(GameLayer::createScene());
});
auto menuItem2 = MenuItemFont::create("Rocket Through");
menuItem2->setFontSizeObj(60);
menuItem2->setPosition(Vec2(_screenSize.width/2, _screenSize.height/5*3));
menuItem2->setCallback([&](Ref *sender) {
Director::getInstance()->replaceScene(RocketThrough::createScene());
});
auto menuItem3 = MenuItemFont::create("");
cocos2d::Vector<MenuItem *> menuItems;
menuItems.pushBack(menuItem1);
menuItems.pushBack(menuItem2);
auto menu1 = Menu::createWithArray(menuItems);
menu1->setPosition(Vec2::ZERO);
this->addChild(menu1);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
//Close the cocos2d-x game scene and quit the application
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
/*To navigate back to native iOS screen(if present) without quitting the application ,do not use Director::getInstance()->end() and exit(0) as given above,instead trigger a custom event created in RootViewController.mm as below*/
//EventCustom customEndEvent("game_scene_close_event");
//_eventDispatcher->dispatchEvent(&customEndEvent);
}
#ifndef __GAMESPRITE_H__
#define __GAMESPRITE_H__
#include "cocos2d.h"
using namespace cocos2d;
class GameSprite : public Sprite {
public:
CC_SYNTHESIZE(Vec2, _nextPosition, NextPosition);
CC_SYNTHESIZE(Vec2, _vector, Vector);
CC_SYNTHESIZE(Touch*, _touch, Touch);
GameSprite();
virtual ~GameSprite();
static GameSprite* gameSpriteWithFile(const char* pszFileName);
virtual void setPosition(const Vec2& pos) override;
float radius();
};
#endif
#include "GameSprite.h"
GameSprite::GameSprite()
{
_vector = Vec2(0, 0);
}
GameSprite::~GameSprite()
{
}
GameSprite *GameSprite::gameSpriteWithFile(const char *pszFileName)
{
auto sprite = new GameSprite();
if (sprite && sprite->initWithFile(pszFileName)) {
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return sprite = nullptr;
}
void GameSprite::setPosition(const Vec2 &pos)
{
Sprite::setPosition(pos);
if (!_nextPosition.equals(pos)) {
_nextPosition = pos;
}
}
float GameSprite::radius()
{
return getTexture()->getContentSize().width * 0.5f;
}
相關文章
- 足球戰術->單刀赴會之prototype篇 (轉)
- 騰訊 、 網易的足球遊戲大戰遊戲
- 簡單的文字設計就能影響遊戲體驗?遊戲中提升玩家體驗的小設計遊戲
- 足球戰術之Builder篇 (轉)UI
- 足球戰術之adapter篇 (轉)APT
- 升級到Java 17沒這麼簡單Java
- 17、flask-圖書簡單館專案Flask
- javascript變數宣告提升簡單介紹JavaScript變數
- iOS 面試大全從簡單到複雜(簡單篇)iOS面試
- cocos2d-x開發之動作遊戲實戰–序篇薦遊戲
- 足球經理類遊戲簡史:讓你在虛擬世界當主教練遊戲虛擬世界
- 三種提升Java程式碼效能的簡單技巧 - levelupJava
- 用unity製作簡單的太空遊戲(2)-簡單炮臺Unity遊戲
- 簡單的傳球遊戲(矩陣)遊戲矩陣
- cocos2d-x遊戲引擎遊戲引擎
- 冠絕巔峰《決勝足球》10月17全平臺開測
- 簡單易懂KVC基礎篇
- 簡單的辦公技巧,也可以提升你的工作效率
- MobileNet 結構簡單微調的一點效能提升
- 關於MongoDB的簡單理解(二)--Java篇MongoDBJava
- 足球戰術之observer及memento篇 (轉)Server
- 簡單塔防小遊戲遊戲
- cocos2d-x學習篇之網路(http)篇HTTP
- 簡單的C# 猜數字遊戲C#遊戲
- 淺談足球遊戲的人工智慧 (轉)遊戲人工智慧
- 關於MongoDB的簡單理解(一)--基礎篇MongoDB
- 足球戰術->全攻全守之visitor篇 (轉)
- 使用 Fuse 和 java 17 編寫一個簡單的檔案系統Java
- 對offline explorer v 1.9的簡單破解 (17千字)
- 抽象工廠:簡單遊戲角色抽象遊戲
- freebsd簡單漢化終結篇[解決了簡單漢化的所有問題(轉)
- 移植一個cocos2d-x遊戲遊戲
- python實現簡單猜單詞遊戲Python遊戲
- cocos2d-x遊戲中音樂音效的處理遊戲
- 遊戲轉化率①:整體簡析篇遊戲
- Redux其實很簡單(原理篇)Redux
- 簡單專案實戰flutter(功能篇)Flutter
- 「LeetCode By Python」簡單篇(一)LeetCodePython