感觉现在时间过的真是飞快,很多人都觉得现在的时间比以前缩短了好多,眨眼间又到了中秋了。通过前面对SimpeCG的了解,现在用C语言绘制一张中秋电子贺卡应该不难了,我们在本篇文章就来试试吧。
不过在这里我们尝试使用SimpleCG的另外一个绘图功能--PencilTurtle,就是小朋友很喜欢的海龟作图方式。这个功能后面再详细介绍,不过很多朋友可能都接触过了,因为早期有很多学习机会附带。
先看看效果图:
运行程序可以在这里下载
http://simplecg.qqpet.com/AnimateMidAutumn2.zip
代码可以在这里查看
全部主体代码如下:
// AnimateMidAutumn.cpp : 定义控制台应用程序的入口点。
//
#include "../import/include/CGBoard.h"
#include "math.h"
extern "C"
{
#include "PencileTurtle.h"
#include "Midi.h"
}
#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MT.lib")
#endif
int g_nWidth = 640; //画面宽度
int g_nHeight= 480; //画面高度
int g_nMusic = 0;
HMIDIOUT g_hMidi = 0;
#define ADDCOLOR(x,y) ((x+y)>255?255:(x+y))
void StartMusic()
{
g_hMidi = SMidOpenMidi();
SetTimbre( g_hMidi, 0, 10 );
g_nMusic = PlaySimpleSongBack( g_hMidi, 0, 90, -1, _T("***1/1-6*5/6+1|*1===|1/1-6*5/6+2|*2===|3/1-6*+3/1-6|+*2/=1*-6=|+44/-6*+1/=|*2===|1/1-6*5/6+1|*1===|1/1-6*5/6+2|*2===|//2**3/1-6/+2**3/1-6|*+2/=1*-6=|+44/-6+*1/=|/2**2===|2-5/7*6/7|/7**+1===|/3232*31|4//4*5432*1|2=/=565|*2===|/3232*31|4//4*5432*1|2=/=565|*2===|2==/22|31*2==|2===|1/1-6*5/6+1|*1===|1/1-6*5/6+2*2===|//2**3/1-6/+2**3/1-6|+*2/=1*-6=|+44/-6+*1/=|/1**2===|2-5/7*6/7|/7**+1===|"));
}
void StopPlayMusic()
{
if( g_nMusic>0 )
{
StopMusic(g_nMusic);
}
SMidCloseMidi( g_hMidi );
}
void DrawMoon()
{
PTSetAngle(0);
setfillcolor(RGB(254,231,122));
PTMoveTo( 500,150 );
PTBeginFill();
PTCircle( 50 );
PTEndFill();
}
void DrawMoonCake( int nX, int nY )
{
int i=0;
int nCount = 18;
setlinecolor(RGB(0xF2,0x90,0x0));
setfillcolor(RGB(0xF8,0x80,0x20));
for(i=0;i<nCount;++i)
{
PTMoveTo( nX,nY );
PTTurnLeft(360 / nCount);
PTMove(100);
PTBeginFill();
PTCircle( 20 );
PTEndFill();
}
setlinewidth(5);
for(i=0;i<nCount;++i)
{
PTMoveTo( nX,nY );
PTTurnLeft(360 / nCount);
PTMove(92);
PTCircle( 20 );
}
setlinewidth(10);
setfillcolor(RGB(0xFF,0x90,0x30));
PTHome();
PTMoveTo( nX,nY+95 );
PTBeginFill();
PTCircle( 95 );
PTEndFill();
//setlinecolor(RGB(162,84,13));
setlinecolor(RGB(248,128,32));
setlinewidth(5);
int j=0;
for(j=0;j<4;++j)
{
PTMoveTo( nX + 90*cos(C_PI/2*j),nY - 90*sin(C_PI/2*j) );
//PTMoveTo( 200,330 );
PTSetAngle(90*j+90);
for(i=0;i<1080;++i)
{
PTTurnLeft(1*((float)i/1080));
PTForward(.15);
}
}
for(j=0;j<4;++j)
{
PTMoveTo( nX + 90*cos(C_PI/2*j),nY - 90*sin(C_PI/2*j) );
PTSetAngle(90*j-90);
for(i=0;i<270;++i)
{
PTTurnRight(1);
PTForward(.6*((float)(270-i)/180));
}
}
}
void DrawWord(int nX,int nY,int nDelay)
{
settextcolor(RGB(228,108,12));
setbackmode(enumBKM_TRANSPARENT);
settextfontWeight(FW_BOLD);
settextfontPointSize(30);
outtextXY( nX-20, nY-80, _T("中"));
if( nDelay>0 )
{
Sleep(nDelay);
ReflushWindow();
}
outtextXY( nX-80, nY-20, _T("秋"));
if( nDelay>0 )
{
Sleep(nDelay);
ReflushWindow();
}
outtextXY( nX-20, nY+40, _T("快"));
if( nDelay>0 )
{
Sleep(nDelay);
ReflushWindow();
}
outtextXY( nX+40, nY-20, _T("乐"));
if( nDelay>0 )
{
Sleep(nDelay);
ReflushWindow();
}
}
void DrawFiveStar(int nX,int nY,int nLen)
{
int i=0;
PTMoveTo( nX,nY );
setlinestyle(PS_NULL);
setfillcolor(RGB(255,255,0));
PTTurnRight(rand()%360);
PTBeginFill();
for(i=0;i<5;++i)
{
PTForward(nLen);
PTTurnRight(144);
}
PTEndFill();
setlinestyle(PS_SOLID);
}
void DrawStar()
{
int i=0;
for(i=0;i<20;++i)
{
int nX = rand()%640;
int nY = rand()%480;
setfillcolor(RGB(245+rand()%10,245+rand()%10,245+rand()%10));
PTMoveTo( nX,nY );
PTBeginFill();
PTCircle( rand()%5 );
PTEndFill();
}
for(i=0;i<8;++i)
{
int nX = rand()%640;
int nY = rand()%480;
DrawFiveStar( nX, nY, 6+rand()%6);
}
}
void DrawLeaves(int nX,int nY, int nSize)
{
setlinecolor(RGB(29,49,84));
setfillcolor(RGB(29,49,84));
PTMoveTo( nX,nY );
PTSetAngle(rand()%80);
int nWidhth = rand()%30+65;
PTBeginFill();
PTArc( nSize, nWidhth );
PTTurnLeft(10);
PTArc( nSize, -nWidhth );
PTEndFill();
}
void DrawBack()
{
int i=0;
setbackcolor(RGB(45,76,130));
ClearDevice();
DrawStar();
setlinecolor(RGB(43,67,115));
setfillcolor(RGB(43,67,115));
PTMoveTo( 0,400 );
PTSetAngle(0);
PTBeginFill();
for(i=0;i<90;++i)
{
PTTurnRight(1);
PTForward(10*((float)(90-i)/90));
}
PTSetAngle(180);
PTForward(380);
PTEndFill();
PTMoveTo( 250,480 );
PTSetAngle(45);
PTBeginFill();
for(i=0;i<90;++i)
{
PTTurnRight(1);
PTForward(20*((float)(90-i)/90));
}
PTSetAngle(-90);
PTForward(380);
PTEndFill();
for(i=0;i<30;++i)
{
DrawLeaves(rand()%600,480, 10+rand()%40);
}
}
void DrawRabbit(int nX, int nY, float fSize )
{
int i=0;
setlinewidth(1);
setlinecolor(RGB(0,0,0));
setfillcolor(RGB(255,255,255));
PTMoveTo( nX,nY );
PTBeginFill();
PTSetAngle(80);
PTArc( -20*fSize, 60 );
PTArc( -10*fSize, 20 );
PTTurnRight(85);
PTArc( -20*fSize, 65 );
PTSetAngle(-40);
PTArc(-16*fSize, 40);
PTTurnLeft(20);
PTArc(-10*fSize, 90);
PTSetAngle(-40);
PTArc(-20*fSize, 69);
PTSetAngle(240);
PTArc(-20, 100);
/*PTForward(34);*/
PTSetAngle(110);
PTArc(-20*fSize, 69);
PTTurnLeft(115);
PTArc(-10*fSize, 90);
PTSetAngle(85);
PTArc(-16*fSize, 40);
PTSetAngle(140);
PTArc( -20*fSize, 55 );
PTArc( -10*fSize, 20 );
PTTurnRight(85);
PTArc( -20*fSize, 65 );
PTEndFill();
}
void DrawRabbit2(int nX, int nY, float fSize )
{
int i=0;
setlinewidth(1);
setlinecolor(RGB(0,0,0));
setfillcolor(RGB(200,200,200));
PTMoveTo( nX+10,nY-25 );
PTBeginFill();
PTSetAngle(30);
PTArc( 35*fSize, -60 );
PTSetAngle(30);
PTArc( -35*fSize, 60 );
PTEndFill();
PTSetAngle(30);
PTArc( 35*fSize, -60 );
setfillcolor(RGB(255,255,255));
PTBeginFill();
PTSetAngle(230);
PTArc( 35*fSize, -60 );
PTSetAngle(230);
PTArc( -35*fSize, 60 );
PTEndFill();
PTMoveTo( nX-60,nY );
PTBeginFill();
PTSetAngle(140);
PTArc( -25*fSize, 80 );
PTSetAngle(-140);
PTArc( 35*fSize, -100 );
PTEndFill();
PTMoveTo( nX-20,nY-20 );
PTBeginFill();
PTSetAngle(180);
PTArc( 50*fSize, -90 );
PTCircle( -6 );
PTTurnRight(50);
PTArc( 80*fSize, -50 );
PTTurnRight(130);
PTArc( 80*fSize, -10 );
PTTurnRight(200);
PTArc( 30*fSize, -130 );
PTEndFill();
setlinestyle(PS_NULL);
setfillcolor(RGB(255,225,200));
PTBeginFill();
PTMoveTo( nX-40,nY-15 );
PTCircle( -7 );
PTEndFill();
setfillcolor(RGB(255,191,191));
PTMoveTo( nX-40,nY-28 );
PTBeginFill();
PTCircle( -3 );
PTEndFill();
setlinestyle(PS_SOLID);
}
void DrawLight(int nX, int nY,float fSize)
{
{
POINT pt[]={{nX,nY},{nX-1.8*fSize,nY-2.3*fSize},{nX+0.5*fSize,nY-4*fSize},{nX+2.6*fSize,nY-4*fSize},{nX+3.6*fSize,nY-fSize},{nX+2*fSize,nY-fSize}};
setfillcolor(RGB(233,145,66));
_fillpolygon(pt,sizeof(pt)/sizeof(pt[0]));
_line(nX+0.5*fSize,nY-4*fSize,nX+2*fSize,nY-fSize);
}
{
POINT pt[]={{nX,nY},{nX+2*fSize,nY-fSize},{nX+3.6*fSize,nY-fSize},{nX+1.6*fSize,nY}};
setfillcolor(RGB(253,202,59));
_fillpolygon(pt,sizeof(pt)/sizeof(pt[0]));
}
setfillcolor(RGB(253,239,120));
_solidcircle(nX+2*fSize,nY-0.5*fSize,0.3*fSize);
}
void DrawProcess()
{
POINT ptLight[10]={0};
int nSize[10]={0};
int i=0;
for(i=0;i<10;++i)
{
ptLight[i].x=rand()%200+400;
ptLight[i].y=rand()%200+200;
nSize[i] = ((float)ptLight[i].y) / 400 *20;
}
bool bIsRunning = true;
StartMusic();
DrawBack();
DrawMoon();
DrawMoonCake(150,150);
DrawWord( 150,150, 500 );
DrawRabbit( 80, 360, 1 );
DrawRabbit( 450, 330, 0.5 );
DrawRabbit2( 550, 300, 1 );
while(bIsRunning&&IsShowingWindow())
{
PTSpeed(0);
DrawBack();
DrawMoon();
DrawMoonCake(150,150);
DrawWord( 150,150, 0 );
DrawRabbit( 80, 360, 1 );
DrawRabbit( 450, 330, 0.5 );
DrawRabbit2( 550, 300, 1 );
for(i=0;i<5;++i)
{
DrawLight(ptLight[i].x,ptLight[i].y, nSize[i]);
if(ptLight[i].y>0)
ptLight[i].y -= 2;
else
ptLight[i].y = rand()%200+200;
nSize[i] = ((float)ptLight[i].y) / 400 *20;
}
ReflushWindow();
Sleep(100);
}
StopPlayMusic();
}
int _tmain(int argc, _TCHAR* argv[])
{
//初始化
if( !ShowingBoard(g_nWidth,g_nHeight, DrawProcess))
return 1;
//关闭图库
CloseBoard();
return 0;
}
其中有很多功能在之前的教程都还没教到,会在后续的文章中介绍,例如文字的输出,海龟作图的方式,以及乐曲的播放等。
在这里顺带说一说乐曲的播放,该播放函数可以播放一般的C大调简谱乐曲,如果有同学想现在尝试该功能的话,我这里大概说一说如何转换任意简谱,通过简单学习,你就能将任意简谱转换成MIDI播放。MIDI播放函数如下:
g_nMusic = PlaySimpleSongBack( g_hMidi, 0, 90, -1, _T("***1/1-6*5/6+1|*1===|1/1-6*5/6+2|*2===|3/1-6*+3/1-6|+*2/=1*-6=|+44/-6*+1/=|*2===|1/1-6*5/6+1|*1===|1/1-6*5/6+2|*2===|//2**3/1-6/+2**3/1-6|*+2/=1*-6=|+44/-6+*1/=|/2**2===|2-5/7*6/7|/7**+1===|/3232*31|4//4*5432*1|2=/=565|*2===|/3232*31|4//4*5432*1|2=/=565|*2===|2==/22|31*2==|2===|1/1-6*5/6+1|*1===|1/1-6*5/6+2*2===|//2**3/1-6/+2**3/1-6|+*2/=1*-6=|+44/-6+*1/=|/1**2===|2-5/7*6/7|/7**+1===|"));
首先我们从网上看一下《明月几时有》(网络引用,版权原作者所有)的简谱如下:
这是四四拍的,这首歌简谱是如何转成我们播放的格式的呢?非常简单! 我们的简谱文本主要有六个特殊字符,分别是+、-、*、/、=、|。就是加减乘除等号,其余就是1、2、3、4、5、6 、7音符,还有一个0休止符。下面介绍详细的转换过程。
首先默认起始状态是C大调、音符是32分音符,此时1、2、3演奏出来的是C大调,就是音符底下和上面都没有点,然后+号升8度,-号降8度,而且输入+、-后影响后面所有的音符,除非再次使用+、-进行调节,乘号*和除号/是改变音符长短,默认是32分音符,输入一个*变成16分音符,再输入*变成8分音符,再一个*就成4分音符,看代码中“ ***1/1-6*5/6+1|*1===|1/1-6*5/6+2|*2===”,开始的三个*就是改变状态为4分音符。然后输出一个1(dou)、紧跟一个/,改变音符为8分音符,然后输出简谱中第二个1(dou),注意第二个1下面的下划线,表示8分音符,接着一个减号-,就把后面降8度,输出的6(啦)就是底下有点的,而且依据前面的音长还是8分音符,到了5(嗦)没有下划线是4分音符,所以要提高音长,我们输入乘号*后再输出5,然后后面的6(啦)又有下划线,音长又变成8分音符,我们输出除号/缩短音长为8分音符后再输出6。接着加号+升8度输出底下没有点的1,|是分段符,跟简谱一样。接着提高音符为4分音符再输出1,就是没有下划线的1(dou)。三个=号对应简谱的-,延长同样的拍。后面类似就不赘述了。对这个演奏有兴趣又没看明白的可以评论告诉我,我后面详细发些例子讲解。理解后还是很简单的。并且可以很方便转换网上的简谱歌曲,例如《罗刹海市》(版权归原作者所有)的简谱片断转换后及播放代码如下,有兴趣的同学可以尝试转换完全。
int _tmain(int argc, _TCHAR* argv[])
{
HMIDIOUT hMidi = SMidOpenMidi();
PlaySimpleSong( hMidi, 0, 60,1,_T("**333|-5/566+116|*06533/53*32|0313|/23*3-6+1011-5665303+11|-3/=5+*11|122-7|6/=76*53|0+*3/3/3532*-6+1-63/+2-7*6653|+/5665*6|6+/1/=1*-6+1*-5| -635|6/65*6/+11*0-115|/3235**3|/0+*3/3|/3532*-6+1|0-*3//+2-7|*6//67*6*53|"));
SMidCloseMidi( hMidi );
return 0;
}
海龟作图方式和文字也在后续文章详细介绍相关函数。请耐心等待。
今天的文章就到这里了,想下载SimpleCG库的同学可以在下面下载。
https://gitcode.net/b2b160/simplecg_demo
安装方法如下