Book-Esenthel-Basics
I started with the Basic section from the mutecode book for Esenthel. Here is the template of an Esenthel application
Created date: 2022-02-22
1 Introduction¶
/******************************************************************************/
void InitPre() // initialize before engine inits
{
INIT(); // call auto-generated function that will setup application name, load engine and project data
}
/******************************************************************************/
bool Init() // initialize after engine is ready
{
// here when engine will be ready you can load your game data
// return false when error occurred
return true;
}
/******************************************************************************/
void Shut() // shut down at exit
{
// this is called when the engine is about to exit
}
/******************************************************************************/
bool Update() // main updating
{
// here you have to process each frame update
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
return true; // continue
}
/******************************************************************************/
void Draw() // main drawing
{
// here you have to tell engine what to draw on the screen
D.clear(AZURE); // clear screen to azure color
D.text (0, 0, "Hello to " ENGINE_NAME " Engine !"); // display text at (0, 0) screen coordinates
}
/******************************************************************************/
2 Random¶
Để có một game thú vị thì cần phải có các events ngẫu nhiên, vì vậy sử dụng Random function sẽ rất thường xuyên trong các games.
EE có class function là Random()
để cho ra các số nguyên và Random.f()
để ra số thực
Trong Update() function
if(Kb.bp(KB_SPACE))
{
number = Random(30);
myColor.set(Random(256), Random(256), Random(256));
myCircle.r = Random.f(); // Random radius size của Circle
myCircle.pos.x = Random.f(-D.w(), D.w()); // Random vị trí của Circle từ bên trái sang phải của màn hình (-1,1)
myCircle.pos.y = Random.f(-D.h(), D.h());
}
Kết quả application đầu tiên với Random một circle và background theo màu sắc như sau (sorry vì màu hơi nhức đầu)
3 Interaction with mouse and keyboard¶
3.1 Mouse position trong class Ms()¶
Trong Update() function có thể update vị trí con trỏ chuột và trong void Draw()
thì cho phép Draw nó lên
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
mousePos = Ms.pos();
return true; // continue
}
void Draw() // main drawing
{
// here you have to tell engine what to draw on the screen
D.clear(BLACK); // Random background color
mousePos.draw(RED);
}
Kết quả như sau:
Ngoài ra cũng có thể giữ khoảng cách giữa con trỏ và Red point
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
mousePos = Ms.pos();
//mousePos.x += 0.1;
mousePos.y += 0.1;
return true; // continue
}
3.2 Mouse clicks¶
Mouse thường có chuột trái, phải và con lăn, ngoài ra cũng có ấn vào chuột giữa hoặc con lăn để rotate.
Bây giờ chỉ hiển thị trỏ chuột khi ấn chuột trái (pushed), nếu bỏ ra (released) thì sẽ biến mất. Dùng màu BLUE để phân biệt
// Tạo các global variable
Vec2 mousePos;
Vec2 mousePos2;
Str myString = "Push left mouse to drag BLUE pointer";
/******************************************************************************/
// Update Game: Các animation trong game cần liên tục update
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
mousePos = Ms.pos();
//mousePos.x += 0.1;
mousePos.y += 0.1;
if (Ms.b(0)) // nếu button, press/pushed=True, chuột trái (0), (1) là chuột phải
{
mousePos2 = Ms.pos();
myString = "Left mouse turned ON";
} else if (Ms.br(0)) // br tức là button release, khi thả chuột trái ra
{
myString = "Left mouse turned OFF";
}
return true; // continue
}
/******************************************************************************/
void Draw() // main drawing
{
// here you have to tell engine what to draw on the screen
D.clear(BLACK); // Random background color
mousePos.draw(RED);
mousePos2.draw(BLUE);
D.text(0.0, 0.0, myString);
}
Ngoài ra còn có các Ms.b*()
khác như
Ms.d
là double click,Ms.bp
là button press trong 1frame
. Nếu sử dụng function này thìpointer
chỉ cập nhật vị trí mới tại thời điểm click chuột chứ không kéo đi được đến vị trí khác dù cho có không thả chuột. Ngược lại thìMs.b
sẽ cập nhật liên tục nếu không thả chuột.- Còn có nhiều
Ms
khác được built sẵn trong Esenthel
3.3 Mouse wheel¶
Sử dụng con lăn của chuột.
Khi sử dụng Ms.wheel
sẽ tạo ra một giá trị delta
(có thể positive và negative) để so sánh distance
giữa các update
Thử thách:
Khi ấn chuột phải thìpointer
sẽ cố định lại.
Sử dụng con lăn để di chuyển chuột theo hàng ngang.
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
if (Ms.b(0)) // nếu button, press/pushed=True, chuột trái (0), (1) là chuột phải
{
mousePos2 = Ms.pos();
myString = "Left mouse turned ON";
} else if (Ms.br(0)) // br tức là button release, khi thả chuột trái ra
{
myString = "Left mouse turned OFF";
}
if (Ms.b(1))
{
mousePos.y +=Ms.wheel() * 0.02; // 0.02 tức là 2% distance
}
return true; // continue
}
Lưu ý khi này cần phải bỏ mousePos=Ms.pos()
trong Update()
nếu không con trỏ sẽ liên tục trở lại vị trí cũ dù cho có sử dụng con lăn.
Change cursor image
3.4 Keyboard¶
Trong các game thường sử dụng phím WASD để di chuyển nhân vật.
Keyboard được sử dụng tương tự như Ms.b*()
, chỉ khác là Kb.b*()
các phím sử dụng như KB_SPACE
Cần chú ý đến bàn phím tiếng anh
QWERTY
hay bàn phím tiếng PhápAZERTY
Hy vọng Esenthel có khả năng tự phân biết. Hoặc chúng ta phải code 1 chút để game tự phân biệt được.Challenge: Tạo 1 Circle di chuyển trên màn hình. Khi ấn phím WASD thì nó sẽ di chuyển 0.05 units màn hình.
Nếu ấn thêm phím Spacebar thì speed của nó sẽ được boost lên, di chuyển với tốc độ 0.1 units và Circle sẽ chuyển từ BLUE sang RED
Vì có 4 phím nên sử dụng switch
, nó tương đương với nhiều if
. Cấu trúc như sau:
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
Tuy nhiên bây giờ mình sẽ sử dụng if
trước cho đơn giản.
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
Ms.cursor(UID(3653639881, 1089848782, 3260974724, 1101079839)); // Change cursor image
myCircle.r = 0.02;
if (Kb.b(KB_W)) myCircle.pos.y += 0.05;
if (Kb.b(KB_S)) myCircle.pos.y -= 0.05;
if (Kb.b(KB_A)) myCircle.pos.x -= 0.05;
if (Kb.b(KB_D)) myCircle.pos.x += 0.05;
// Khi Circle chạm phải viền màn hình thì sẽ đi về vị trí ban đầu
// Sử dụng Display width or Display height của màn hình
if (myCircle.pos.x > D.w()) myCircle.pos.x= -D.w();
if (myCircle.pos.x < -D.w()) myCircle.pos.x= D.w();
if (myCircle.pos.y > D.h()) myCircle.pos.y= -D.h();
if (myCircle.pos.y < -D.h()) myCircle.pos.y= D.h();
return true; // continue
}
/******************************************************************************/
void Draw() // main drawing
{
// here you have to tell engine what to draw on the screen
D.clear(BLACK); // Random background color
myCircle.draw(BLUE);
}
Bây giờ sẽ add thêm chế độ Super Saiya khi sử dụng spacebar. Chỉ cần thêm biến speed
và myColor
để có thể thay đổi khi sử dụng phím SpaceBar
Circle myCircle;
Color myColor;
int speed;
/******************************************************************************/
// Update Game: Các animation trong game cần liên tục update
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
Ms.cursor(UID(3653639881, 1089848782, 3260974724, 1101079839)); // Change cursor image
myCircle.r = 0.02;
speed = (Kb.b(KB_SPACE)) ? 2 : 1; // Sử dụng ternary expression cho nhanh
myColor = (Kb.b(KB_SPACE)) ? RED : BLUE;
if (Kb.b(KB_W)) myCircle.pos.y += 0.05*speed;
if (Kb.b(KB_S)) myCircle.pos.y -= 0.05*speed;
if (Kb.b(KB_A)) myCircle.pos.x -= 0.05*speed;
if (Kb.b(KB_D)) myCircle.pos.x += 0.05*speed;
3.5 Delta time in Game¶
Time.d()
sẽ giúp cho game hoạt động tương đồng trên các máy tính khác nhau. Vì có máy là 60FPS có máy là 30FPS. Time.d()
sẽ cho kết quả của unit per second.
Bài tập di chuyển con trỏ sẽ được thay vì dùng 0.05*speed
sẽ dùng Time.d()*speed
if (Kb.b(KB_W)) myCircle.pos.y += Time.d()*speed;
if (Kb.b(KB_S)) myCircle.pos.y -= Time.d()*speed;
if (Kb.b(KB_A)) myCircle.pos.x -= Time.d()*speed;
if (Kb.b(KB_D)) myCircle.pos.x += Time.d()*speed;
Kết quả animation sẽ smooth hơn so với dùng 0.05.
4 Shapes¶
Esenthel có các shape có sẵn như Circle, Edge, Rectangle
Để vẽ 1 đường line thì cần dùng Edge2
, 2 tức là trong môi trường 2D.
Challenge: Tạo một vòng tròn, có 1 hoặc 2 lines di chuyển như đồng hồ
- Vẽ Circle
- Vẽ Line là Second
- Vẽ Line là Minute
- Vẽ Line là Hour
- Sử dụng
Time.curTime()
để lấy được thời điểm theo thời gian thực. - Một Circle là 180 độ, tương đương với 60 giây –> 3 độ/giây –> Một delta time sẽ di chuyển 3 độ.
- Lưu ý
Sin
vàCos
trong Esenthel sử dụng Radian chứ không phải degree. Tức làSin(30 độ)
phải ghi làSin(PI/6)
Hiện tại mình chỉ vẽ cho second
cho đơn giản.
Edge2 secondLine;
int speed=1;
float x=0.0;
float y=0.5;
float beta;
float clockRadius=0.5;
Circle clockBound;
TextStyleParams ts;
/******************************************************************************/
// Update Game: Các animation trong game cần liên tục update
bool Update() // main updating
{
if(Kb.b(KB_ESC))return false; // exit if escape on the keyboard pressed
clockBound.r = clockRadius; // Tạo vòng tròn với bán kính là 0.5
beta =(PI/2-speed*Time.curTime()*2*PI/60);
x = Cos(beta)*clockRadius;
y = Sin(beta)*clockRadius;
// Update vị trí của kim giây.
secondLine.set(Vec2(0, 0), Vec2(x, y));
speed=(Kb.b(KB_SPACE)) ? 10 : 1;
ts.color=YELLOW; // Khai báo màu cho Clock TExt
return true; // continue
}
/******************************************************************************/
void Draw() // main drawing
{
// here you have to tell engine what to draw on the screen
D.clear(BLACK); // Random background color
D.text(0, 0.7, S+"Degree: " + beta*180/PI);
D.text(0, 0.8, S+"Running time (second): "+ Time.curTime());
clockBound.draw(WHITE);
secondLine.draw(RED, 0.005); // Color then width
D.text(ts, 0, 0.55, "12");
D.text(ts,0, -0.55, "6");
D.text(ts,0.55, 0, "3");
D.text(ts,-0.55, 0, "9");
}
Kết quả tạo đồng hồ với kim giây. Sử dụng phím SPACEBAR để boost tốc độ lên 10 lần cho dễ kiểm tra.
5 Cuts, collision¶
Cuts
là một functon rất có ích trong game, xác định 2 vật thể có chạm nhau hay không. Bây giờ sẽ tạo 1 game nhỏ để áp dụng chức năng này
Challenge: Cho Random các Enemy có hình dạng là Rectangle RED xuất hiện trên màn hình. Dùng BLUE Circle để thu thập các Enemy, điểm sẽ được tăng dần
1. Sử dụng code từ bài Keyboard Book-Esenthel-Basics.
2. Tạo Random các Shape Rect (hiện tại chỉ 1 enemy) trên màn hình
3. Biến mất Shape Rect khi Circle chạm vào.Random các shape. Esenthel-Book-Basics
Đoạn code dưới đây tạo Rect có x từ 0.1 đến 0.2 và y từ -0.2 đến 0.2
Để Random position của Rect thì sử dụng Random.f
từ Display
trái sang phải, trên xuống dưới.
// Enemy Rectangle
float randomXpos = Random.f(-D.w(), D.w());
float randomYpos = Random.f(-D.h(), D.h());
float randomSize = Random.f(0.1, 0.3);
enemyRect.setX(randomXpos, randomXpos+randomSize);
enemyRect.setY(randomYpos, randomYpos+randomSize);
Tuy nhiên Random Rect như vậy có nhược điểm là các RECT xuất hiện quá nhanh, và không kiểm soát được
Bây giờ chỉ Tạo Rect mới khi Circle chạm vào nó. Sử dụng if Circle Cuts Rect
thì tạo Rect
mới.
if (Cuts(myCircle, enemyRect))
{
randomXpos = Random.f(-D.w(), D.w());
randomYpos = Random.f(-D.h(), D.h());
randomSize = Random.f(0.1, 0.3);
enemyRect.setX(randomXpos, randomXpos+randomSize);
enemyRect.setY(randomYpos, randomYpos+randomSize);
}
Sản phẩm:
Để tăng độ khó thì Enemy cần có khả năng di chuyển. Luật chơi là Enemy chỉ di chuyển khi Circle lại gần 20%, nó có tốc độ đi khoảng 80 - 120% so với Circle. Nó có khả năng đi trở lại màn hình như Circle
// Tạo các global variable
Circle myCircle;
Rect enemyRect;
Color myColor;
int speed;
float randomXpos=0.1;
float randomYpos=0.1;
float randomSize=0.1;
/******************************************************************************/
// Update Game: Các animation trong game cần liên tục update
bool Update() // main updating
{
if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
// My Circle position
myCircle.r = 0.02;
speed = (Kb.b(KB_SPACE)) ? 2 : 1; // Sử dụng ternary expression cho nhanh
myColor = (Kb.b(KB_SPACE)) ? YELLOW : BLUE;
if (Kb.b(KB_W))
{
myCircle.pos.y += Time.d()*speed; // Di chuyển Circle dựa theo WASD
// Nếu Cicle gần Enemy 20% thì Enemy sẽ di chuyển giống như bàn phím với tốc độ 0.8 đến 1.2
if (Abs(myCircle.pos.y - enemyRect.centerY())<0.2) enemyRect.moveY(Time.d()*Random.f(0.8, 1.2));
}
if (Kb.b(KB_S))
{
myCircle.pos.y -= Time.d()*speed;
if (Abs(myCircle.pos.y - enemyRect.centerY())<0.2) enemyRect.moveY(-Time.d()*Random.f(0.8, 1.2));
}
if (Kb.b(KB_A))
{
myCircle.pos.x -= Time.d()*speed;
if (Abs(myCircle.pos.x - enemyRect.centerX())<0.2) enemyRect.moveX(-Time.d()*Random.f(0.8, 1.2));
}
if (Kb.b(KB_D))
{
myCircle.pos.x += Time.d()*speed;
if (Abs(myCircle.pos.x - enemyRect.centerX())<0.2) enemyRect.moveX(Time.d()*Random.f(0.8, 1.2));
}
// Khi Circle chạm phải viền màn hình thì sẽ đi về vị trí ban đầu
// Sử dụng Display width or Display height của màn hình
if (myCircle.pos.x > D.w()) myCircle.pos.x= -D.w();
if (myCircle.pos.x < -D.w()) myCircle.pos.x= D.w();
if (myCircle.pos.y > D.h()) myCircle.pos.y= -D.h();
if (myCircle.pos.y < -D.h()) myCircle.pos.y= D.h();
// Không cho Rect đi xuyên màn hình
if (enemyRect.centerX() > D.w()) enemyRect.setX(-D.w(), -D.w()+randomSize);
if (enemyRect.centerX() < -D.w()) enemyRect.setX( D.w(), D.w()+randomSize);
if (enemyRect.centerY() > D.h()) enemyRect.setY(-D.h(), -D.h()+randomSize);
if (enemyRect.centerY() < -D.h()) enemyRect.setY( D.h(), D.h()+randomSize);
// Create Enemy Rectangle when Circle collide
if (Cuts(myCircle, enemyRect)) // Khi Circle chạm vào Rect sẽ tạo 1 Rect tại vị trí khác
{
randomXpos = Random.f(-D.w(), D.w());
randomYpos = Random.f(-D.h(), D.h());
randomSize = Random.f(0.1, 0.3);
enemyRect.setX(randomXpos, randomXpos+randomSize);
enemyRect.setY(randomYpos, randomYpos+randomSize);
}
return true; // continue
}

6 Next¶
Now I will go to the chapter two of this book in the other note, because this note is already long.
Backlinks¶
The following pages link to this page:
Created : Feb 22, 2022
Recent Posts
- 2024-11-02: BUỔI 10 - Phân tích thị trường
- 2024-11-02: BUỔI 11 - Phân tích thị trường
- 2024-11-02: BUỔI 12 - Phân tích sóng tăng
- 2024-11-02: BUỔI 13 - Phân tích hỏi đáp
- 2024-11-02: BUỔI 14 - Yếu tố kiểm soát
- 2024-11-02: BUỔI 15 - Hỏi đáp
- 2024-11-01: BUỔI 6 - Ôn lại và bổ sung
- 2024-11-01: BUỔI 7 - Chiến thuật Trend
- 2024-11-01: BUỔI 8 - Công thức điểm vào lệnh
- 2024-11-01: K2023 - BUỔI 9 - Quy trình vào lệnh