Pada entri ini, saya akan berbagi sebuah simulasi.
Simulasi ini tentang sebuah karakter yang berusaha menuju istana, atau tempat harta karun, ya terserah. Jadi karakter ada di seberang sungai, dan istananya ada di daratan seberang. Untuk menuju istana, karakter harus menuju tombol pembuka jembatan, kemudian setelah jembatan terbuka, karakter menyeberang dan harus menuju ke tempat pengambilan kunci istana agar bisa masuk. Tetapi tidak semudah itu, karakter harus menghindari para penjaga, bila perlu harus melawannya agar selamat. Untuk yang ingin melihat video simulasinya dan penjelasan lebih lengkap silakan menuju ke link di bawah ini:
Berikut ini adalah tampilannya:
Simulasi yang saya buat termasuk simulasi yang sangat sederhana. Saya membuatnya menggunakan openGL dengan bahasa C++. Ada beberapa hal yang perlu dikembangkan dalam simulasi ini agar lebih baik, contohnya:
1. Pengejaran oleh penjaga seharusnya berdasarkan range,
2. Prioritas menuju target dapat membuat karakter sewaktu-waktu terjebak dalam pohon-pohon yang posisinya acak. Sehingga perlu aturan khusus agar karakter semakin pintar.
Jika kalian ingin mengembangkan simulasi ini, silakan kalian gunakan kode di bawah ini:
Kode di bawah ini hanya variabel, konstanta, dan fungsi yang berkaitan dengan simulasi ini saja. Jika belum mengerti cara untuk mengimplementasikannya, silakan gabungkan dengan kode dasar implementasi pada link di bawah ini:
const int n2 = 102;
const int n = 100;
const int river_width=13; //axa harus ganjil
const int castle_width=5; //axa harus ganjil
const int sight_range=3; //axa harus ganjil
const double forest_density=0.1; //kerapatan pohon
const int guard_number=11; //jumlah penjaga
const int pembobot=1; //pembobot arah
const int pembobot_hindar=n; //pembobot arah
const double win_rate=0.9; //rate player menang fight
int init=1, in_area=0, gameover=0; //status
int s[n2][n2], s1[n2][n2]; //terrain
int targetpos[4][2];
int playerpos[2], guardpos[guard_number][2]; //posisi
int direction[sight_range][sight_range]; //bobot arah
int guardlive[guard_number]; //guardian yang hidup
int on_bridge[guard_number+1]; //status ada di atas jembatan
int to_target=0;
//warna
GLfloat nothing[3] = {0.5, 0.3, 0.0};
GLfloat river[3] = {0.2, 0.4, 0.8};
GLfloat bridge[3] = {0.3, 0.3, 0.3};
GLfloat tree[3] = {0.0, 0.8, 0.0};
GLfloat castle[3] = {0.8, 0.8, 0.0};
GLfloat player[3] = {1.0, 1.0, 1.0};
GLfloat guard[3] = {1.0, 0.0, 0.0};
GLfloat button[3] = {0.8, 0.8, 0.0};
void resetdir(void){ //pemberian bobot
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
direction[i][j]=pembobot;
}
}
}
void measuredir(int a[], int b[]){ //pemberian bobot
resetdir();
if(a[0]>b[0]){ //jika sasaran di utara
direction[2][0]+=pembobot;
direction[2][1]+=pembobot;
direction[2][2]+=pembobot;
}
else if(a[0]<b[0]){ //jika sasaran di selatan
direction[0][0]+=pembobot;
direction[0][1]+=pembobot;
direction[0][2]+=pembobot;
}
if(a[1]>b[1]){ //jika sasaran di timur
direction[0][2]+=pembobot;
direction[1][2]+=pembobot;
direction[2][2]+=pembobot;
}
else if(a[1]<b[1]){ //jika sasaran di barat
direction[0][0]+=pembobot;
direction[1][0]+=pembobot;
direction[2][0]+=pembobot;
}
//jika ada penjaga lebih baik menghindar
if(s[b[0]-1][b[1]+1]==6||s[b[0]][b[1]+1]==6||s[b[0]+1][b[1]+1]==6){
direction[0][0]+=pembobot_hindar;
direction[1][0]+=pembobot_hindar;
direction[2][0]+=pembobot_hindar;
}
if(s[b[0]-1][b[1]-1]==6||s[b[0]][b[1]-1]==6||s[b[0]+1][b[1]-1]==6){
direction[0][2]+=pembobot_hindar;
direction[1][2]+=pembobot_hindar;
direction[2][2]+=pembobot_hindar;
}
if(s[b[0]+1][b[1]-1]==6||s[b[0]+1][b[1]]==6||s[b[0]+1][b[1]+1]==6){
direction[0][0]+=pembobot_hindar;
direction[0][1]+=pembobot_hindar;
direction[0][2]+=pembobot_hindar;
}
if(s[b[0]-1][b[1]-1]==6||s[b[0]-1][b[1]]==6||s[b[0]-1][b[1]+1]==6){
direction[2][0]+=pembobot_hindar;
direction[2][1]+=pembobot_hindar;
direction[2][2]+=pembobot_hindar;
}
}
void userDraw() {
glBegin(GL_POINTS);
if(init==1){
//initialization
srand(time(NULL));
targetpos[0][0]=n*90/100;
targetpos[0][1]=n*10/100;
s[targetpos[0][0]][targetpos[0][1]]=7;
targetpos[1][0]=n/2;
targetpos[1][1]=(int)(1/(1+exp(-1*((double)targetpos[1][0]-n/2)))*n*0.5+(n/4));
targetpos[2][0]=n*10/100;
targetpos[2][1]=n*90/100;
s[targetpos[2][0]][targetpos[2][1]]=7;
targetpos[3][0]=n*90/100;
targetpos[3][1]=n*90/100;
for (int i = 1; i < n2-1; i++) {
int sigmoid_y = (int)(1/(1+exp(-1*((double)i-n/2)))*n*0.5+(n/4));
//pembuatan sungai
for(int j = (river_width/2+1) - river_width; j < (river_width/2+1); j++){
for(int k = (river_width/2+1) - river_width ; k < (river_width/2+1); k++){
if(s[i-j][sigmoid_y-k] != 2){
s[i-j][sigmoid_y-k] = 1;
}
}
}
}
//pembuatan castle
for(int i = (castle_width/2+1) - castle_width; i < (castle_width/2+1); i++){
for(int j = (castle_width/2+1) - castle_width ; j < (castle_width/2+1); j++){
s[targetpos[3][0]-i][targetpos[3][1]-j] = 4;
}
}
//pembuatan player
playerpos[0]=n*10/100;
playerpos[1]=n*10/100;
s[playerpos[0]][playerpos[1]]=5;
//pembuatan pohon
for (int i = 1; i < n2-1; i++) {
for (int j = 1; j < n2-1; j++) {
if(s[i][j]!=1&&s[i][j]!=2&&s[i][j]!=4&&s[i][j]!=5&&s[i][j]!=7){
if((double)rand()/RAND_MAX<forest_density){
s[i][j]=3;
}
}
}
}
//pembuatan penjaga
for(int i=0; i<guard_number; i++){
guardlive[i]=1;
do{
guardpos[i][0]=(rand() % n)+1;
guardpos[i][1]=(rand() % n)+1;
}while(s[guardpos[i][0]][guardpos[i][1]]==1||s[guardpos[i][0]][guardpos[i][1]]==2||s[guardpos[i][0]][guardpos[i][1]]==3||s[guardpos[i][0]][guardpos[i][1]]==4||s[guardpos[i][0]][guardpos[i][1]]==5||s[guardpos[i][0]][guardpos[i][1]]==7||guardpos[i][1]<=(int)(1/(1+exp(-1*((double)guardpos[i][0]-n/2)))*n*0.5+(n/4)));
s[guardpos[i][0]][guardpos[i][1]]=6;
}
init=0;
}
else{
//update state
if(gameover==0){
//perjalanan player
measuredir(targetpos[to_target],playerpos);
int tempdir[2]={0,0};
double tempscore=0.0;
for(int i=-1;i<2;i++){
for(int j=-1;j<2;j++){
if(s[playerpos[0]+i][playerpos[1]+j] == 0 || s[playerpos[0]+i][playerpos[1]+j] == 2 || s[playerpos[0]+i][playerpos[1]+j] == 4 || s[playerpos[0]+i][playerpos[1]+j] == 7 && (playerpos[0]+i > 0 && playerpos[0]+i <= n && playerpos[1]+j > 0 && playerpos[1]+j <= n)){
double r = (double)rand()/RAND_MAX*direction[i+1][j+1];
if(tempscore < r){
tempscore = r;
tempdir[0] = i;
tempdir[1] = j;
}
}
}
}
if(on_bridge[0]==1){
s[playerpos[0]][playerpos[1]]=2;
}
else{
s[playerpos[0]][playerpos[1]]=0;
}
playerpos[0]+=tempdir[0];
playerpos[1]+=tempdir[1];
if(s[playerpos[0]][playerpos[1]]==4){
gameover=1;
printf("GAME OVER!\n");
}
else{
//pengecekan bidak di posisi target
if(playerpos[0]==targetpos[to_target][0]&&playerpos[1]==targetpos[to_target][1]){
if(to_target==0){
for(int j = (river_width/2+1) - river_width; j < (river_width/2+1); j++){
for(int k = (river_width/2+1) - river_width ; k < (river_width/2+1); k++){
s[targetpos[1][0]-j][targetpos[1][1]-k] = 2;
}
}
}
to_target++;
}
//pengecekan bidak di atas jembatan
if(s[playerpos[0]][playerpos[1]]==2){
on_bridge[0]=1;
}
else{
on_bridge[0]=0;
}
s[playerpos[0]][playerpos[1]]=5;
//pengecekan bidak berada di wilayah istana
if(playerpos[1]>(int)(1/(1+exp(-1*((double)playerpos[0]-n/2)))*n*0.5+(n/4))){
if(in_area==0){
printf("WARNING! INTRUDER!\n",playerpos[0],playerpos[1],(int)(1/(1+exp(-1*((double)playerpos[0]-n/2)))*n*0.5+(n/4)));
}
in_area=1;
}
}
//perjalanan penjaga
if(in_area==0){
//saat player belum melewati jembatan
for(int a=0;a<guard_number;a++){
if(guardlive[a]==1){
int r;
int r2;
do{
r=(int)rand()%3-1;
r2=(int)rand()%3-1;
}while(s[guardpos[a][0]+r][guardpos[a][1]+r2]==1||s[guardpos[a][0]+r][guardpos[a][1]+r2]==3||s[guardpos[a][0]+r][guardpos[a][1]+r2]==4||s[guardpos[a][0]+r][guardpos[a][1]+r2]==6||s[guardpos[a][0]+r][guardpos[a][1]+r2]==7||guardpos[a][0]+r<1||guardpos[a][0]+r>n||guardpos[a][1]+r2<1||guardpos[a][1]+r2>n);
if(on_bridge[a+1]==1){
s[guardpos[a][0]][guardpos[a][1]]=2;
}
else{
s[guardpos[a][0]][guardpos[a][1]]=0;
}
guardpos[a][0]+=r;
guardpos[a][1]+=r2;
if(s[guardpos[a][0]][guardpos[a][1]]==5){
if((double)rand()/RAND_MAX<win_rate){
guardlive[a]=0;
s[guardpos[a][0]][guardpos[a][1]]=5;
printf("WIN FIGHT!\n"); //player membunuh penjaga
}
else{
s[guardpos[a][0]][guardpos[a][1]]=6;
gameover=1;
printf("GAME OVER!\n"); //player ditangkap
}
}
else{
if(s[guardpos[a][0]][guardpos[a][1]]==2){
on_bridge[a+1]=1;
}
else{
on_bridge[a+1]=0;
}
s[guardpos[a][0]][guardpos[a][1]]=6;
}
}
}
}else{
//saat player sudah melewati jembatan
for(int a=0;a<guard_number;a++){
if(guardlive[a]==1){
int find=0;
measuredir(playerpos, guardpos[a]);
int tempdir[2]={0,0};
double tempscore=0.0;
for(int i=-1;i<2;i++){
for(int j=-1;j<2;j++){
if(s[guardpos[a][0]+i][guardpos[a][1]+j]==0||s[guardpos[a][0]+i][guardpos[a][1]+j]==2||s[guardpos[a][0]+i][guardpos[a][1]+j]==5&&(guardpos[a][0]+i>0&&guardpos[a][0]+i<=n&&guardpos[a][1]+j>0&&guardpos[a][1]+j<=n)){
double r=(double)rand()/RAND_MAX*direction[i+1][j+1];
if(s[guardpos[a][0]+i][guardpos[a][1]+j]==5){
tempscore=r;
tempdir[0]=i;
tempdir[1]=j;
find=1;
break;
}
else if(tempscore<r){
tempscore=r;
tempdir[0]=i;
tempdir[1]=j;
}
}
}
if(find==1){
break;
}
}
if(on_bridge[a+1]==1){
s[guardpos[a][0]][guardpos[a][1]]=2;
}
else{
s[guardpos[a][0]][guardpos[a][1]]=0;
}
guardpos[a][0]+=tempdir[0];
guardpos[a][1]+=tempdir[1];
if(s[guardpos[a][0]][guardpos[a][1]]==5){
if((double)rand()/RAND_MAX<win_rate){
guardlive[a]=0;
s[guardpos[a][0]][guardpos[a][1]]=5;
printf("WIN FIGHT!\n"); //player membunuh penjaga
}
else{
s[guardpos[a][0]][guardpos[a][1]]=6;
gameover=1;
printf("GAME OVER!\n"); //player ditangkap
}
}
else{
if(s[guardpos[a][0]][guardpos[a][1]]==2){
on_bridge[a+1]=1;
}
else{
on_bridge[a+1]=0;
}
s[guardpos[a][0]][guardpos[a][1]]=6;
}
}
}
}
}
}
//draw
for (int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++){
if(s[i][j] == 1){
glColor3fv(river);
}else if(s[i][j] == 2){
glColor3fv(bridge);
}else if(s[i][j] == 3){
glColor3fv(tree);
}else if(s[i][j] == 4){
glColor3fv(castle);
}else if(s[i][j] == 5){
glColor3fv(player);
}else if(s[i][j] == 6){
glColor3fv(guard);
}else if(s[i][j] == 7){
glColor3fv(button);
}else{
glColor3fv(nothing);
}
glVertex2f(i, j);
}
}
delay();
glEnd();
}
Terima kasih. Silakan komen jika ada yang perlu ditanyakan.
No comments:
Post a Comment