[Cocos3.0 Tutorial] Use the Cocos2d-x-3.0 game engine. Write a Tower Defender Game.(Part04)

Previous: http://www.cocos2d-x.org/forums/6/topics/53677

6.Game Hud

    First, we are going to adjust the screen, since we have created some objects outside the tile map. A piece of black area will truly make people frustrating and will cause some bugs.
Image Title

    Type these codes in the AppDelete.cpp:

bool AppDelegate::applicationDidFinishLaunching()
{
    ……
glview->setDesignResolutionSize(864, 640, kResolutionExactFit);
    ……
}

Image Title
Full screen

    Now we are going to create another two pairs of classes, Tower.h / .cpp and GameHud.h / .cpp, so we get some chance to choose different types of defender. (Just like how we build different types of enemies, you can do it yourself once you master the skill.) And deploy them on the map.

Image Title

Uncomment the code in the DataModel.h of the tutorial part 02:

//Vector<Tower*> towers;    // We will deal with it later.

In the Tower.h:

#pragma once
#include "cocos2d.h"
#include "Creep.h"

class Tower: public Sprite 
{
public:
	int range;
	Sprite* sprite;
	Creep* target;
	Sprite * selSpriteRange;
	Creep* getClosesTarget();
	CREATE_FUNC(Tower);
};

class MachineGunTower : public Tower 
{
public:
	static Tower* tower();
	bool virtual init();
	void towerLogic(float dt);
};

    As you can see, here we create a basic class first, contain its range, closest target, and inherit from the Sprite, Creep. Next we create the class MachineGunTower which inherits from the Tower we created before.

In Tower.cpp:

#include "Tower.h"
#include "DataModel.h"

Tower* MachineGunTower::tower()
{
	Tower* tower = Tower::create();
	tower->sprite = Sprite::create("MachineGunTurret.png");
	tower->setScale(0.5);
	tower->addChild(tower->sprite, 0);
	tower->range = 200;
	tower->schedule(schedule_selector(towerLogic), 0.2);
	return tower;
}

    Just like the old time. ‘MachineGunTower’ inherits from the ‘tower’, and uploads the picture material, set its scale and range. At last space, use the ‘schedule’ function to refresh the function ‘towerLogic’ every 0.2 second.

bool MachineGunTower::init()
{
	if (!Sprite::init()) 
	{
		return false;
	}
	return true;
}


void MachineGunTower::towerLogic(float dt)
{
	// Coming soon…
}

Uncommon the code in the DataModel.h of the tutorial part 02:

//GameHUD* _gameHUDLayer;  // We will deal with it later.

In the GameHUD.h

#pragma once
#include "cocos2d.h"

USING_NS_CC;

class GameHUD: public Layer 
{
public:
	Sprite* background;
	Sprite* selSpriteRange;
	Sprite* selSprite;
	Vector<Sprite*> movableSprites;
	static GameHUD* _sharHUD;
	virtual bool init();
	static GameHUD* shareHUD();
	CREATE_FUNC(GameHUD);
	virtual void onEnter();
	bool onTouchBegan(Touch *touch, Event *event);
	void onTouchMoved(Touch *touch, Event *event);
	void onTouchEnded(Touch* touch, Event* event);
};

Image Title
    Yes, it should be dragged everywhere, so we need ‘Listener Event’ (onTouchXXX).

And in GameHUD.cpp:

#include "GameHUD .h"
#include "DataModel.h"

GameHUD* GameHUD::_sharHUD;

bool GameHUD::init()
{
	if (!Layer::init()) 
	{
		return false;
	}

	Size winSize = CCDirector::getInstance()->getWinSize();

	// Draw the background of the game HUD
	CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA8888);
	background = Sprite::create("hud.png");
	background->setScaleX (2);
	background->setAnchorPoint(ccp(0, 0));
	this->addChild(background); 
	//CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_Default);

Image Title
Background

// Load the images of the towers we’ll have and draw them to the game HUD layer
Image Title
MachineGunTower…

	Vector<String*> images;
	images.pushBack(StringMake("MachineGunTurret.png"));
	images.pushBack(StringMake("MachineGunTurret.png"));
	images.pushBack(StringMake("MachineGunTurret.png"));
	images.pushBack(StringMake("MachineGunTurret.png"));
	for (int i = 0; i < images.size(); ++i)
	{
		String* image = images.at(i);
		auto *sprite = Sprite::create(image->getCString());
		float offsetFraction = ((float)(i + 1)) / (images.size() + 1);
		sprite->setScale(0.6);
		sprite->setPosition(ccp(winSize.width*offsetFraction, 35));
		this->addChild(sprite);
		movableSprites.pushBack(sprite);
	}

	return true;
}

GameHUD* GameHUD::shareHUD()
{
	if (_sharHUD == NULL)
	{
		_sharHUD = GameHUD::create();
	}

	return _sharHUD;
}

void GameHUD::onEnter()
{
	Layer::onEnter();

	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);

	listener->onTouchBegan = CC_CALLBACK_2(GameHUD::onTouchBegan, this);
	listener->onTouchMoved = CC_CALLBACK_2(GameHUD::onTouchMoved, this);
	listener->onTouchEnded = CC_CALLBACK_2(GameHUD::onTouchEnded, this);

	auto dispatcher = Director::getInstance()->getEventDispatcher();

	dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
	//dispatcher->addEventListenerWithFixedPriority(listener, 0);

}

bool GameHUD::onTouchBegan(Touch *touch, Event *event)
{
	Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));

	Sprite * newSprite = NULL;
	for each(Sprite* sprite in this->movableSprites)
	//for (int i = 0; i < movableSprites.size(); i++)  // Use this if your VC doesn’t support C++11
	{
	// Sprite* sprite = (Sprite*)(movableSprites.at(i));  // Use this if your VC doesn’t support C++11

Rect pos_rect = Rect((sprite->getPositionX()-sprite->getContentSize().width/2), (sprite->getPositionY()-sprite->getContentSize().height/2), sprite->getContentSize().width, sprite->getContentSize().height);
// This determines the area which you can drag our ‘tower’
		float xMin = pos_rect.getMinX();
		float xMax = pos_rect.getMaxX();
		float yMIn = pos_rect.getMinY();
		float yMax = pos_rect.getMaxY();
		if (pos_rect.containsPoint(touchLocation))
		{
			DataModel *m = DataModel::getModel();
			//m.gestureRecognizer.enabled = NO;
			selSpriteRange = Sprite::create("Range.png");
			selSpriteRange->setScale(4);
			this->addChild(selSpriteRange, -1);
			selSpriteRange->setPosition(sprite->getPosition());

			newSprite = Sprite::createWithTexture(sprite->getTexture()); //sprite;
			newSprite->setPosition(sprite->getPosition());
			newSprite->setScale(0.6);
			selSprite = newSprite;
			this->addChild(newSprite);
		}
	}
		
	return true;
}

void GameHUD::onTouchMoved(Touch* touch,Event* event) 
{
	Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));

	Point oldTouchLocation = touch->getPreviousLocationInView();
	oldTouchLocation = Director::getInstance()->convertToGL(oldTouchLocation);
	oldTouchLocation = this->convertToNodeSpace(oldTouchLocation);

	Point translation = ccpSub(touchLocation,oldTouchLocation);

	if (selSprite) 
	{
		Point newPos = selSprite->getPosition()+translation;
		selSprite->setPosition(newPos);
		selSpriteRange->setPosition(newPos);

		DataModel *m = DataModel::getModel();
		Point touchLocationInGameLayer = m->_gameLayer->convertTouchToNodeSpace(touch);

		BOOL isBuildable = m->_gameLayer->canBuildOnTilePosition(touchLocationInGameLayer);
		if (isBuildable) 
		{
			selSprite->setOpacity(200);
		}
		else 
		{
			selSprite->setOpacity(50);
		}
	}
}

To be continue…

Next: http://www.cocos2d-x.org/forums/6/topics/53962


05.png (12.4 KB)


00.png (125.8 KB)


01.png (727.1 KB)


02.png (26.7 KB)


03.png (263.2 KB)


04.png (49.0 KB)

@Suigintou. I get crash when run to here

    Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));

@Hoangtaiki Move on to the next tutorial. This page doesn’t complete the whole function.

I am looking forward from you soon :smiley:
@Suigintou

@Hoangtaiki Oh~I mean you need to move on to the part05 to finish “void GameHUD::onTouchEnded”

I have same issue