axmol/examples/SimpleSnake/Classes/SimpleSnakeScene.cpp

326 lines
9.4 KiB
C++

/*
* Copyright (c) 2022 @aismann; Peter Eismann, Germany; dreifrankensoft
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "SimpleSnakeScene.h"
#include <time.h>
#include <string>
USING_NS_CC;
struct Snake
{
int x, y;
} s[snakeBodies + StartBodies];
struct Fruit
{
int x, y;
} f;
// Print useful error message instead of segfaulting when files are not there.
static void problemLoading(const char* filename)
{
printf("Error while loading: %s\n", filename);
printf(
"Depending on how you compiled you might have to add 'Resources/' in front of filenames in "
"HelloWorldScene.cpp\n");
}
inline void setNodeIgnoreDesignScale(cocos2d::Node* node)
{
CCASSERT(node, "node pointer cannot be null.");
Size actualFrameSize = Director::getInstance()->getOpenGLView()->getFrameSize();
Size actualWinSize = Director::getInstance()->getWinSizeInPixels();
node->setScaleX(actualWinSize.width / actualFrameSize.width);
node->setScaleY(actualWinSize.height / actualFrameSize.height);
}
// on "init" you need to initialize your instance
bool SimpleSnake::init()
{
//////////////////////////////
// 1. super init first
if (!Scene::init())
{
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin();
auto safeArea = Director::getInstance()->getSafeAreaRect();
auto safeOrigin = safeArea.origin;
offset = Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y);
/////////////////////////////
// 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(SimpleSnake::menuCloseCallback, this));
if (closeItem == nullptr || closeItem->getContentSize().width <= 0 || closeItem->getContentSize().height <= 0)
{
problemLoading("'CloseNormal.png' and 'CloseSelected.png'");
}
else
{
float x = safeOrigin.x + safeArea.size.width - closeItem->getContentSize().width / 2;
float y = safeOrigin.y + closeItem->getContentSize().height / 2;
closeItem->setPosition(Vec2(x, y));
}
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
/////////////////////////////
// 3. add your codes below...
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(SimpleSnake::onKeyPressed, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
// add a label shows "Hello World"
// create and initialize a label
auto label1 = Label::createWithTTF("Simple Snake", "fonts/arial.ttf", 24);
if (label1 == nullptr)
{
problemLoading("'fonts/arial.ttf'");
}
else
{
// position the label on the center of the screen
label1->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height - label1->getContentSize().height*2 - visibleSize.height/2));
// add the label as a child to this layer
this->addChild(label1, 1);
}
auto label2 = Label::createWithTTF("Eat as fast as you can!", "fonts/arial.ttf", 24);
if (label2 == nullptr)
{
problemLoading("'fonts/arial.ttf'");
}
else
{
// position the label on the center of the screen
label2->setPosition(
Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height - label2->getContentSize().height * 3 - visibleSize.height/2));
// add the label as a child to this layer
this->addChild(label2, 1);
}
// add "ADXE" splash screen"
auto sprite = Sprite::create("ADXE_white.png"sv);
setNodeIgnoreDesignScale(sprite);
if (sprite == nullptr)
{
problemLoading("'ADXE_white.png'");
}
else
{
// position the sprite on the center of the screen
sprite->setPosition(offset);
// add the sprite as a child to this layer
this->addChild(sprite, 9);
auto drawNode = DrawNode::create();
drawNode->setPosition(Vec2(0, 0));
addChild(drawNode, 20);
drawNode->drawRect(safeArea.origin, safeArea.origin + safeArea.size, Color4F::BLUE);
}
srand(time(0));
mydraw = DrawNode::create();
addChild(mydraw, 10);
background = Sprite::create("Background.png");
background->setPosition(offset);
background->setScale(1.1);
addChild(background, 0);
f.x = 10;
f.y = 10;
s[0].x = 20;
s[0].y = 20;
char buffer[1024];
for (int i = 0; i < snakeBodies+1; i++)
{
myScore[i] = 0.0;
sprintf(buffer, "%i: %f", i + 1, myScore[i]);
myScoreLabel[i] = Label::createWithTTF(std::string(buffer), "fonts/arial.ttf", 20);
myScoreLabel[i]->setAnchorPoint(Vec2(0, 1));
myScoreLabel[i]->setPosition(Vec2(10, origin.y + visibleSize.height - 10 - i * 20));
this->addChild(myScoreLabel[i], 1);
}
myScoreLabel[snakeBodies]->setString("");//"Eat as fast as you can!");
scheduleUpdate();
return true;
}
void SimpleSnake::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
switch (keyCode)
{
case cocos2d::EventKeyboard::KeyCode::KEY_LEFT_ARROW:
if (dir != 2)
dir = 1;
break;
case cocos2d::EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
if (dir != 1)
dir = 2;
break;
case cocos2d::EventKeyboard::KeyCode::KEY_UP_ARROW:
if (dir != 3)
dir = 0;
break;
case cocos2d::EventKeyboard::KeyCode::KEY_DOWN_ARROW:
if (dir != 0)
dir = 3;
break;
default:
break;
}
}
void SimpleSnake::menuCloseCallback(Ref* sender)
{
Director::getInstance()->end();
}
void SimpleSnake::update(float delta)
{
static float runTime = 0;
static bool finish = false;
runTime += delta;
endLevelTime += delta;
if (finish)
{
float myScale = runTime + 1.1;
if (myScale > 3.0)
myScale = 3.0;
background->setScale(myScale);
return;
}
if (runTime > level)
{
for (int i = num; i > 0; --i)
{
s[i] = s[i - 1];
}
switch (dir)
{
case 0:
s[0].y++;
if (s[0].y >= M) s[0].y = 0;
break;
case 1:
s[0].x--;
if (s[0].x < 0) s[0].x = N - 1;
break;
case 2:
s[0].x++;
if (s[0].x >= N) s[0].x = 0;
break;
case 3:
s[0].y--;
if (s[0].y < 0) s[0].y = M - 1;
break;
default:
break;
}
if ((s[0].x == f.x) && (s[0].y == f.y))
{
bool posOk;
do
{
posOk = true;
f.x = rand() % N;
f.y = rand() % M;
for (int i = 0; i < num; i++)
{
if (f.x == s[i].x && f.y == s[i].y)
{
posOk = false;
break;
}
}
} while (!posOk);
// next level
num++;
if (num >= (snakeBodies + StartBodies - 1))
{
myScoreLabel[snakeBodies]->setString("!!! FINISH !!!");
finish = true;
drawAll(finish);
}
level -= 0.01;
startLevelTime = 0.0;
endLevelTime = startLevelTime;
}
runTime = 0;
}
if (!finish)
{
drawAll(finish);
}
}
void SimpleSnake::drawAll(bool finish)
{
// score
char buffer[124];
myScore[num - StartBodies] = endLevelTime;
sprintf(buffer, "%i: %f", num - StartBodies + 1, myScore[num - StartBodies]);
myScoreLabel[num - StartBodies]->setString(buffer);
mydraw->clear();
// draw snake body
for (int i = 1; i < num; i++)
{
mydraw->drawDot(Vec2(size / 2 + s[i].x * size, size / 2 + s[i].y * size), size / 2, Color4B::BLUE);
}
//draw snake head
mydraw->drawDot(Vec2(size / 2 + s[0].x * size, size / 2 + s[0].y * size), size / 2, Color4B::MAGENTA);
if (!finish)
{
// draw food
mydraw->drawDot(Vec2(size / 2 + f.x * size, size / 2 + f.y * size), size / 2, Color4B::GREEN);
}
}