Tank 클래스
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 | #pragma once #include <cocos2d.h> USING_NS_CC; class Tank : public Node { private: bool isLeft; bool isRight; bool isUp; bool isDown; float rotation; float bulletdelay; float barreldegree; float trackdelay; float trackdirection; Point tankdir; Point dir; public: Tank(); ~Tank(); bool init(); void update(float dt); void onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event); void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event); void onMouseMove(EventMouse* event); void onMouseDown(EventMouse* event); float getdegree(); Point getdir(); Point gettankdir(); void bulletsmoke(Point expos, int team); CREATE_FUNC(Tank); }; | cs |
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 | #include "Tank.h" #include "Bullet.h" Tank::Tank() { isLeft = false; isRight = false; isUp = false; isDown = false; rotation = 0; // 탱크이동방향 barreldegree = 0; // 포신 각도 -> 탄에 넘겨주기위해 bulletdelay = 1.0f; // 탄 연속발사 딜레이를 만들기위해 trackdelay = 0; // 바퀴자국 딜레이 dir = Point::ZERO; // 포신방향 tankdir = Point::ZERO; // 탱크방향 } Tank::~Tank() { } bool Tank::init() { Sprite* Tank = Sprite::create("res/tank/tankGreen.png"); Tank->setPosition(200, 200); addChild(Tank, 2, "mytank"); Sprite* Barrel = Sprite::create("res/tank/barrelGreen.png"); Barrel->setPosition(Tank->getPositionX(), Tank->getPositionY()); addChild(Barrel, 3, "barrel"); Barrel->setAnchorPoint(Point::ANCHOR_MIDDLE_BOTTOM); EventListenerKeyboard* listener = EventListenerKeyboard::create(); listener->onKeyPressed = CC_CALLBACK_2(Tank::onKeyPressed, this); listener->onKeyReleased = CC_CALLBACK_2(Tank::onKeyReleased, this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this); auto mouselistener = EventListenerMouse::create(); mouselistener->onMouseMove = CC_CALLBACK_1(Tank::onMouseMove, this); mouselistener->onMouseDown = CC_CALLBACK_1(Tank::onMouseDown, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(mouselistener, this); scheduleUpdate(); return true; } void Tank::update(float dt) { auto Tank = getChildByName("mytank"); auto Barrel = getChildByName("barrel"); // 바퀴자국 trackdelay += dt; if (isUp || isDown) { if (trackdelay > 0.5f) { auto track = Sprite::create("res/tank/track.png"); addChild(track, 0, "track"); track->setPositionX(Tank->getPositionX()); track->setPositionY(Tank->getPositionY()); track->setRotation(rotation); auto seq = Sequence::create(DelayTime::create(1.5f), FadeOut::create(0.5f), RemoveSelf::create(true), NULL); track->runAction(seq); trackdelay = 0; } } // 이동, 회전 float speed = 150.0f * dt; tankdir = Point(sinf(CC_DEGREES_TO_RADIANS(rotation)), cosf(CC_DEGREES_TO_RADIANS(rotation))); if (isUp) { Tank->setPosition(Tank->getPosition() + tankdir * speed); Barrel->setPosition(Tank->getPositionX(), Tank->getPositionY()); } if (isDown) { Tank->setPosition(Tank->getPosition() - tankdir * speed); Barrel->setPosition(Tank->getPositionX(), Tank->getPositionY()); } if (isLeft) { rotation -= 80.0f * dt; Tank->setRotation(rotation); } if (isRight) { rotation += 80.0f * dt; Tank->setRotation(rotation); } // 탄발사 딜레이 bulletdelay += dt; } void Tank::onKeyPressed(EventKeyboard::KeyCode keyCode, Event * event) { switch (keyCode) { case EventKeyboard::KeyCode::KEY_W: isUp = true; break; case EventKeyboard::KeyCode::KEY_S: isDown = true; break; case EventKeyboard::KeyCode::KEY_A: isLeft = true; break; case EventKeyboard::KeyCode::KEY_D: isRight = true; break; } } void Tank::onKeyReleased(EventKeyboard::KeyCode keyCode, Event * event) { switch (keyCode) { case EventKeyboard::KeyCode::KEY_W: isUp = false; break; case EventKeyboard::KeyCode::KEY_S: isDown = false; break; case EventKeyboard::KeyCode::KEY_A: isLeft = false; break; case EventKeyboard::KeyCode::KEY_D: isRight = false; break; } } // 마우스 방향대로 포신이 움직임 void Tank::onMouseMove(EventMouse * event) { auto Barrel = getChildByName("barrel"); Point cur = Director::getInstance()->convertToGL(event->getLocation()); Point myPos = Barrel->getPosition(); dir = cur - myPos; dir.normalize(); barreldegree = atan2f(dir.x, dir.y); Barrel->setRotation(CC_RADIANS_TO_DEGREES(barreldegree)); } // 마우스 클릭하면 탄발사 void Tank::onMouseDown(EventMouse * event) { if (bulletdelay >= 1.0f) { // 탄생성 auto newBullet = Bullet::create(); addChild(newBullet, 1, "bullet"); bulletdelay = 0; // 스모크 애니메이션 auto smokeSprite = Sprite::create("res/smoke/smokeGrey0.png"); addChild(smokeSprite, 4, "smoke"); auto Barrel = getChildByName("barrel"); smokeSprite->setPosition(Barrel->getPosition() + dir * 70); Animation* smoke = Animation::create(); smoke->setDelayPerUnit(0.15f); for (int i = 0; i <= 5; i++) { std::string fileName = StringUtils::format("res/smoke/smokeGrey%d.png", i); smoke->addSpriteFrameWithFile(fileName); } Animate* animate = Animate::create(smoke); auto sp = Spawn::create(animate, FadeOut::create(1.0f), NULL); auto seq = Sequence::create(sp, RemoveSelf::create(true), NULL); smokeSprite->runAction(seq); } } float Tank::getdegree() { return barreldegree; } Point Tank::getdir() { return dir; } Point Tank::gettankdir() { return tankdir; } // void Tank::bulletsmoke(Point expos, int team) { Sprite* smokeSprite; if(team == 1) smokeSprite = Sprite::create("res/smoke/smokeOrange0.png"); else if(team == 2) smokeSprite = Sprite::create("res/smoke/smokeYellow0.png"); addChild(smokeSprite, 4, "smoke"); smokeSprite->setPosition(expos); Animation* smoke = Animation::create(); smoke->setDelayPerUnit(0.15f); for (int i = 0; i <= 5; i++) { std::string fileName; if(team == 1) fileName = StringUtils::format("res/smoke/smokeOrange%d.png", i); else if(team == 2) fileName = StringUtils::format("res/smoke/smokeYellow%d.png", i); smoke->addSpriteFrameWithFile(fileName); } Animate* animate = Animate::create(smoke); auto sp = Spawn::create(animate, FadeOut::create(1.0f), NULL); auto seq = Sequence::create(sp, RemoveSelf::create(true), NULL); smokeSprite->runAction(seq); } | cs |
이제 기본적인 것들은 대충 알기때문에 주석을 많이 달지는 않았다.
탱크와 포신을 생성하고 키입력을 받아 탱크를 이동(포신도 같이 이동)하며
마우스를 따라 포신이 돌아간다. 마우스 클릭시 탄이 발사되며 연기 애니메이션이 발생한다.
탱크의 이동과 포신의 회전은 수학적인개념(삼각함수)이 조금 들어가는데 이해 안가시는 분들은
블로그에 써둔 글을 참고하시면 좋을 것 같다.
cos, sin으로 그 방향으로 이동해야할 x, y 값을 구하고 atan로 각도를 구하는 것이다.
Bullet 클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #pragma once #include <cocos2d.h> USING_NS_CC; class Bullet : public Node { private: bool fire; Point barreldir; float degree; public: Bullet(); ~Bullet(); bool init(); void update(float dt); CREATE_FUNC(Bullet); }; | cs |
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 | #include "Bullet.h" #include "Tank.h" #include "Barrier.h" #include "GameLayer.h" Bullet::Bullet() { fire = false; degree = 0; barreldir = Point::ZERO;; } Bullet::~Bullet() { } bool Bullet::init() { Sprite* bullet1 = Sprite::create("res/bullet/bulletOrange.png"); addChild(bullet1, 0, "bullet"); scheduleUpdate(); return true; } void Bullet::update(float dt) { auto tank = (Tank*)getParent(); auto barrel = (Sprite*)tank->getChildByName("barrel"); auto bullet1 = (Sprite*)getChildByName("bullet"); // 발사하면 탱크의 포신방향으로 회전 if (!fire) { barreldir = tank->getdir(); degree = tank->getdegree(); // 이름과 다르게 라디안임 setPosition(barrel->getPosition()); setRotation(CC_RADIANS_TO_DEGREES(degree)); fire = true; } setPositionX(getPositionX() + sinf(degree) * 400.0f * dt); setPositionY(getPositionY() + cosf(degree) * 400.0f * dt); // 화면밖으로 나가면 if (getPositionX() < -50 || getPositionX() > 1300 || getPositionY() < -50 || getPositionY() > 750) { this->removeFromParent(); } else { // 탄충돌 auto gl = (GameLayer*)tank->getParent(); auto br = (Barrier*)gl->getChildByName("basicbarrier"); auto tank = (Tank*)gl->getChildByName("mytank"); // 장애물 충돌 int brownnum = br->getbrown(); int beigenum = br->getbeige(); int treenum = br->gettree(); int drumnum = br->getdrum(); Rect bulletRect = bullet1->getBoundingBox(); bulletRect.origin += getPosition(); bulletRect.origin += getParent()->getPosition(); //log("%.2f : %.2f", bulletRect.origin.x, bulletRect.origin.y); for (int i = 0; i < brownnum; i++) { auto barrier = br->getChildByTag(i); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 1); this->removeFromParent(); break; } } for (int i = 0; i < beigenum - 100; i++) { auto barrier = br->getChildByTag(i + 100); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 1); this->removeFromParent(); break; } } for (int i = 0; i < treenum - 200; i++) { auto barrier = br->getChildByTag(i + 200); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 1); this->removeFromParent(); break; } } for (int i = 0; i < drumnum - 300; i++) { auto barrier = br->getChildByTag(i + 300); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 1); this->removeFromParent(); break; } } // 적탱크와 충돌 auto et = gl->getChildByName("enemytank")->getChildByName("enemytank"); auto eb = gl->getChildByName("enemytank")->getChildByName("enemybarrel"); Rect etRect = et->getBoundingBox(); if (bulletRect.intersectsRect(etRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 1); auto bl = Blink::create(0.5f, 3); auto sq = Sequence::create(bl, Show::create(), NULL); et->runAction(sq); bl = Blink::create(0.5f, 3); sq = Sequence::create(bl, Show::create(), NULL); eb->runAction(sq); this->removeFromParent(); } } } | cs |
탄은 발사시 포신방향으로 스스로 날아가며 장애물 및 적 탱크와 충돌하면 삭제된다.
EnemyTank 클래스
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 | #include "EnemyTank.h" #include "GameLayer.h" #include "Tank.h" #include "EnemyBullet.h" #include "UILayer.h" EnemyTank::EnemyTank() { tankspeed = 150.0f; trackdelay = 0; bulletdelay = 0; } EnemyTank::~EnemyTank() { } bool EnemyTank::init() { Sprite* Tank = Sprite::create("res/tank/tankBlack.png"); Tank->setPosition(1100, 540); addChild(Tank, 2, "enemytank"); Sprite* Barrel = Sprite::create("res/tank/barrelBlack.png"); Barrel->setPosition(Tank->getPositionX(), Tank->getPositionY()); Barrel->setRotation(-90.0f); addChild(Barrel, 3, "enemybarrel"); Barrel->setAnchorPoint(Point::ANCHOR_MIDDLE_BOTTOM); scheduleUpdate(); return true; } void EnemyTank::update(float dt) { auto EnemyTank = getChildByName("enemytank"); auto Barrel = getChildByName("enemybarrel"); // 기본이동 if (EnemyTank->getPositionY() > 540) tankspeed = -150.0f; else if (EnemyTank->getPositionY() < 140) tankspeed = 150.0f; EnemyTank->setPositionY(EnemyTank->getPositionY() + tankspeed * dt); Barrel->setPositionY(EnemyTank->getPositionY()); // 바퀴자국 trackdelay += dt; if (trackdelay > 0.5f) { auto track = Sprite::create("res/tank/track.png"); addChild(track, 0, "track"); track->setPositionX(EnemyTank->getPositionX()); track->setPositionY(EnemyTank->getPositionY()); auto seq = Sequence::create(DelayTime::create(1.5f), FadeOut::create(0.5f), RemoveSelf::create(true), NULL); track->runAction(seq); trackdelay = 0; } // 탱크충돌 auto gl = (GameLayer*)getParent(); auto mytank = gl->getChildByName("mytank")->getChildByName("mytank"); auto mybarrel = gl->getChildByName("mytank")->getChildByName("barrel"); Point mtp = mytank->getPosition(); Point etp = EnemyTank->getPosition(); Point bdir = etp - mtp; float tblength = bdir.length(); if (tblength < mytank->getContentSize().width / 2 + EnemyTank->getContentSize().width / 2) { tankspeed *= -1; EnemyTank->setPositionY(EnemyTank->getPositionY() + tankspeed * dt * 10); Barrel->setPositionY(EnemyTank->getPositionY()); auto mytankNode = (Tank*)gl->getChildByName("mytank"); Point tankdir = mytankNode->gettankdir(); mytank->setPosition(mytank->getPosition() - tankdir * 150.0f * dt * 10); mybarrel->setPosition(mytank->getPosition()); auto bl = Blink::create(0.5f, 3); auto sq = Sequence::create(bl, Show::create(), NULL); EnemyTank->runAction(sq); bl = Blink::create(0.5f, 3); sq = Sequence::create(bl, Show::create(), NULL); Barrel->runAction(sq); bl = Blink::create(0.5f, 3); sq = Sequence::create(bl, Show::create(), NULL); mytank->runAction(sq); bl = Blink::create(0.5f, 3); sq = Sequence::create(bl, Show::create(), NULL); mybarrel->runAction(sq); auto ul = (UILayer*)gl->getParent()->getChildByName("ul"); ul->hpdown(); if (ul->gethp() >= 0) { ul->getChildByTag(ul->gethp())->removeFromParent(); } } // 적탱크 탄발사 bulletdelay += dt; if (bulletdelay >= 1.0f) { // 탄생성 auto newBullet = EnemyBullet::create(); addChild(newBullet, 1, "bullet"); bulletdelay = 0; } } | cs |
기본 적 하나 생성하고 위 아래로만 이동
나머지는 기존 탱크와 흡사하고 유저탱크와 충돌시 충돌체크를 추가하였다.
EnemyBullet 클래스
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 | #include "EnemyBullet.h" #include "EnemyTank.h" #include "Tank.h" #include "GameLayer.h" #include "Barrier.h" #include "UILayer.h" EnemyBullet::EnemyBullet() { fire = false; barreldir = Point::ZERO; } EnemyBullet::~EnemyBullet() { } bool EnemyBullet::init() { Sprite* bullet1 = Sprite::create("res/bullet/bulletYellow.png"); addChild(bullet1, 0, "bullet"); scheduleUpdate(); return true; } void EnemyBullet::update(float dt) { auto et = (EnemyTank*)getParent(); auto enemytank = et->getChildByName("enemytank"); auto enemybarrel = et->getChildByName("enemybarrel"); auto bullet1 = (Sprite*)getChildByName("bullet"); if (!fire) { setPosition(enemybarrel->getPosition()); setRotation(-90.0f); barreldir = Point(-1, 0); fire = true; } setPositionX(getPositionX() - 400.0f * dt); // 화면밖으로 나가면 if (getPositionX() < -50 || getPositionX() > 1300 || getPositionY() < -50 || getPositionY() > 750) { this->removeFromParent(); } else { // 탄충돌 auto gl = (GameLayer*)et->getParent(); auto br = (Barrier*)gl->getChildByName("basicbarrier"); auto tank = (Tank*)gl->getChildByName("mytank"); int brownnum = br->getbrown(); int beigenum = br->getbeige(); int treenum = br->gettree(); int drumnum = br->getdrum(); Rect bulletRect = bullet1->getBoundingBox(); bulletRect.origin += getPosition(); bulletRect.origin += getParent()->getPosition(); //log("%.2f : %.2f", bulletRect.origin.x, bulletRect.origin.y); for (int i = 0; i < brownnum; i++) { auto barrier = br->getChildByTag(i); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 2); this->removeFromParent(); break; } } for (int i = 0; i < beigenum - 100; i++) { auto barrier = br->getChildByTag(i + 100); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 2); this->removeFromParent(); break; } } for (int i = 0; i < treenum - 200; i++) { auto barrier = br->getChildByTag(i + 200); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 2); this->removeFromParent(); break; } } for (int i = 0; i < drumnum - 300; i++) { auto barrier = br->getChildByTag(i + 300); Rect barrierRect = barrier->getBoundingBox(); if (bulletRect.intersectsRect(barrierRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 2); this->removeFromParent(); break; } } // 자신의 탱크와 충돌 auto mytank = tank->getChildByName("mytank"); auto Barrel = tank->getChildByName("barrel"); Rect tankRect = mytank->getBoundingBox(); if (bulletRect.intersectsRect(tankRect)) { Point expos = Point(getPositionX(), getPositionY()); expos += barreldir * 20.0f; tank->bulletsmoke(expos, 2); auto bl = Blink::create(0.5f, 3); auto sq = Sequence::create(bl, Show::create(), NULL); mytank->runAction(sq); bl = Blink::create(0.5f, 3); sq = Sequence::create(bl, Show::create(), NULL); Barrel->runAction(sq); auto ul = (UILayer*)gl->getParent()->getChildByName("ul"); ul->hpdown(); if (ul->gethp() >= 0) { ul->getChildByTag(ul->gethp())->removeFromParent(); } this->removeFromParent(); } } } | cs |
기존 Bullet 클래스와 크게 다른 점은 없다.
처음만들 때 설계를 잘못하여 손이 조금 갈 것 같아서 그냥 enemybullet 클래스를 만듬.
내용은 크게 뭐 없는데 코드가 길어서 너무 내용이 많아졌다.
실행화면
완전 완성은 아니지만 그래도 어느정도 틀은 대충 구현된 것 같다.
이제 그래도 좀 게임같아 보이니 실력이 쪼끔 늘긴 했나보다.
'프로그래밍 공부 > cocos2d-x' 카테고리의 다른 글
Tank Game 만들기 - 2 (0) | 2018.03.28 |
---|---|
Tank Game 만들기 - 1 (0) | 2018.03.28 |
Running Game 만들기 - 2 (0) | 2018.03.28 |
Running Game 만들기 - 1 (0) | 2018.03.28 |
기타 잡다한 팁들 (0) | 2018.03.28 |