MMORPG大型游戲設計與開發(服務器 游戲場景 事件)


今天第星期天,知識是永遠是學習不完的,所以今天這部分算比較輕松,同時也希望大家會有一個好的周末。場景事件即場景的回調,和別的事件一樣是在特定的條件下產生的,前面也介紹過場景的各種事件,今天詳細的說一說這些事件的具體作用。

游戲截圖

  

場景事件

  一個完整的對象一般都擁有事件,至於什么是事件在這里就不多解釋了。在場景中的事件在天龍/武俠世界中的事件包括場景初始化、場景定時器、場景退出、玩家進入場景、角色升級、角色死亡、角色重生、場景通知、任務接受檢查、NPC對話默認事件、NPC事件列表事件。

  1、場景初始化(scene init)

    場景初始化事件,負責副本場景的數據維護、負責副本定時器的開啟、負責城市入口的掛接、調用腳本初始化函數。

  2、場景定時器(scene timer)

    負責定時器數據的處理,一般會調用到腳本的相應函數。

  3、場景退出(scene quit)

    場景退出一般是清理數據的作用,首先調用腳本的場景退出函數,然后移除所有對象。移除的對象包括玩家、怪物、寵物、操作台、掉落包。

  4、玩家進入(player enter)

    一個玩家進入場景產生的事件,一般調用腳本函數處理該事件。

  5、玩家升級(player level up)

    玩家升級后的回調,試想一下玩家升級后會有哪些數據的改變?場景中有哪些數據需要更新?是不是這里的玩家升級事件也就包括了其他數據的改變?

  6、玩家死亡(player death)

    玩家死亡一般伴隨着許多數據的改變,如常見的金錢掉落,物品掉落等等,還有玩家死亡可能會觸發任務狀態的改變,或一個劇情等等。

  7、玩家復活(player relive)

    玩家的復活事件,是不是玩家復活的時候常見的數據直接在邏輯中就實現了,還是要放到事件函數中?我們這里常說的事件函數一般都是指調用腳本,調用腳本其實為了能夠頻繁的改動數據。

  8、玩家斷線(player disconnect)

    斷線是一個痛苦的事情,特別是在我們玩的正開心的時候,但是怎么也比不過一些實在的數據處理的時候,如天龍八部中離線事件中把玩家交易的完全處理放到了這里。

  9、場景通知(scene notify)

    一開始一聽這個事件的時候我也曾覺得很迷茫,但是看了具體代碼的時候才知道在游戲中是為副本場景來服務的,只有當副本已經初始化完成才會收到該消息用來傳送玩家到副本中。

  10、任務接受檢查事件(mission accept check)

    要接受一個任務會有條件的,如人物等級的限制、所在場景、事件限制等等。

  11、NPC默認對話框事件(npc default dialog)

    如果是可以交互的NPC則會有對話框來表現這種交互,如果還有默認的操作則將默認操作的選項顯示出來。

  12、NPC默認事件列表(npc default event list)

    默認事件列表是指NPC默認的一些事件,這些事件在經過該回調正確的檢查之后才顯示正確的選項。

算法(歸並和基數排序)

  1、歸並排序

    並排序算法實現復雜,因為二路歸並算法需要的臨時空間較大,所以常常用在外部序中。(其核心的思想為將兩個或兩個以上的元素有序序列合並為一個有序序列)

    並算法是一種穩定的排序算法。

    code.

#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <inttypes.h>

/**
 * 歸並排序算法實現復雜,因為二路歸並算法需要的臨時空間較大,所以常常用在外部
 * 排序中。(其核心的思想為將兩個或兩個以上的元素有序序列合並為一個有序序列)
 * 歸並算法是一種穩定的排序算法。
 */

//將source數組中的元素復制到dest數組中,其中,length為長度,first是目標數組的起始位置
void copyarray(int32_t source[], int32_t dest[], int32_t length, int32_t first);
//歸並排序
void mergesort(int32_t array[], int32_t left, int32_t right);
//合並兩個子序列中的元素
void merge(int32_t array[], int32_t left, int32_t right);
//數組打印
void displayarray(int32_t array[], int32_t length);

int32_t main(int32_t argc, char *argv[]) {
  int32_t array[] = {100, 35, 23, 6, 81, 33, 125, 378, 199};
  int32_t length = sizeof(array) / sizeof(array[0]);
  printf("before sort: ");
  displayarray(array, length);
  mergesort(array, 0, length - 1);
  printf("after sort: ");
  displayarray(array, length);
  return 0;
}

void copyarray(int32_t source[], int32_t dest[], int32_t length, int32_t first) {
  int32_t i, j = first;
  for (i = 0; i < length; ++i) {
    dest[j] = source[i];
    ++j;
  }
}

void mergesort(int32_t array[], int32_t left, int32_t right) {
  int32_t i;
  if (left < right) {
    i = (left + right) / 2;
    mergesort(array, left, i);
    mergesort(array, i + 1, right);
    merge(array, left, right);
  }
}

void merge(int32_t array[], int32_t left, int32_t right) {
  int32_t begin1, begin2, middle, k = 0, length;
  int32_t *pointer = NULL;
  begin1 = left;
  middle = (left + right) / 2;
  begin2 = middle + 1;
  length = right - left + 1;
  pointer = (int32_t *)malloc(length * sizeof(int32_t));
  if (NULL == pointer) return;
  while (begin1 <= middle && begin2 <= right) {
    if (array[begin1] < array[begin2]) {
      pointer[k++] = array[begin1++];
    } else {
      pointer[k++] = array[begin2++];
    }
  }
  while (begin1 <= middle) pointer[k++] = array[begin1++];
  while (begin2 <= right) pointer[k++] = array[begin2++];
  copyarray(pointer, array, length, left);
  if (pointer != NULL) free(pointer);
  pointer = NULL;
}

void displayarray(int32_t array[], int32_t length) {
  int32_t i;
  for (i = 0; i < length; ++i)
    printf("%4d", array[i]);
  printf("\n");
}

    result.

  2、基數排序(比較復雜)

    數排序算法實現比較復雜,它是一種多關鍵字的排序算法,屬於分類排序。因為基數序算法不需要過多比較,所以在數據較多的情況下,采用基數排序算法的效率要高於他的排序算法。

    基數排序也是一種穩定的算法。

    code.

#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

/**
 * 基數排序算法實現比較復雜,它是一種多關鍵字的排序算法,屬於分類排序。因為基數
 * 排序算法不需要過多比較,所以在數據較多的情況下,采用基數排序算法的效率要高於
 * 其他的排序算法。
 */

#define SIZEMAX 200 //待排序元素的最大個數
#define N 10 //待排序元素的實際個數
#define NUMBERKEY_MAX 6 //關鍵字項數的最大值
#define RADIX 10 //關鍵字基數,10表示十進制數字可以分為十組

typedef struct listcell_struct {
  int32_t key[NUMBERKEY_MAX]; //關鍵字
  int32_t next;
} listcell_t; //靜態鏈表的節點,存放待排序的元素

typedef struct list_struct {
  listcell_t data[SIZEMAX]; //存儲元素,data[0]為頭節點
  int32_t keynumber; //每個元素的當前關鍵字個數
  int32_t length; //靜態鏈表的當前長度
} list_t; //靜態鏈表,存放元素序列

typedef int32_t addr[RADIX]; //指針數組的類型,用來指向每個鏈表的第一個節點和最后一個節點

void displaylist(list_t L); //輸出鏈表中的元素
void display_staticlist(list_t L); //以靜態鏈表的形式輸出元素
void initlist(list_t *list, int32_t dest[], int32_t length);
int32_t transchar(char _char); //將字符轉換為數字
void distribute(listcell_t data[], int32_t i, addr f, addr r); //分配
void collect(listcell_t data[], addr f, addr r); //收集
void radixsort(list_t *L);

int32_t main(int32_t argc, char *argv[]) {
  int32_t array[N] = {131, 23, 56, 34, 2, 11, 19, 38, 22, 33};
  list_t L;
  initlist(&L, array, N);
  printf("need sort number is %d, key number is %d\n", L.length, L.keynumber);
  printf("before sort static list: ");
  display_staticlist(L);
  printf("before sort list: \n");
  displaylist(L);
  radixsort(&L);
  printf("after sort: \n");
  displaylist(L);
  return 0;
}

//按數組序號形式輸出靜態鏈表
void displaylist(list_t L) {
  int32_t i, j;
  printf("no  key  addr \n");
  for (i = 1; i <= L.length; ++i) {
    printf("%2d  ", i);
    for (j = L.keynumber - 1; j >= 0; --j) {
      printf("%c", L.data[i].key[j]);
    }
    printf("  %d\n", L.data[i].next);
  }
}

//按鏈表形式輸出靜態鏈表
void display_staticlist(list_t L) {
  int32_t i = L.data[0].next, j;
  while (i) {
    for (j = L.keynumber - 1; j >= 0; --j)
      printf("%c", L.data[i].key[j]);
    printf(" ");
    i = L.data[i].next;
  }
  printf("\n");
}

//初始化靜態鏈表L
void initlist(list_t *L, int32_t array[], int32_t length) {
  char _char1[NUMBERKEY_MAX] , _char2[NUMBERKEY_MAX];
  int32_t i, j;
  int32_t max = array[0];
  for (i = 1; i < length; ++i) { //將最大的元素存入max
    if (max < array[i]) max = array[i];
  }
  (*L).keynumber = (int32_t)(log10(max)) + 1; //求字關鍵字的個數
  (*L).length = length; //待排序個數
  for (i = 1; i <= length; ++i) {
    //itoa(array[i - 1], _char1 , 10); //將整型轉換為字符,並存入_char
    sprintf(_char1, "%d", array[i - 1]);
    //如果_char的長度<max的位數,則在_char前補'0'
    for (j = strlen(_char1); j < (*L).keynumber; ++j) {
      strcpy(_char2, "0");
      strcat(_char2, _char1);
      strcpy(_char1, _char2);
    }
    //將每個元素的個位數存入key,作為關鍵字
    for (j = 0; j < (*L).keynumber; ++j) {
      (*L).data[i].key[j] = _char1[(*L).keynumber - 1 - j];
    }
  }
  for (i = 0; i < (*L).length; ++i)
    (*L).data[i].next = i + 1;
  (*L).data[(*L).length].next = 0;
}

int32_t transchar(char _char) {
  return _char - '0';
}

//為data數組中的第i個關鍵字key[i]建立radix個子表,使同一子表中元素的key[i]相同
//f[0...radix - 1]和r[0...radix - 1]分別指向各個子表中第一個和最后一個元素
void distribute(listcell_t data[], int32_t i, addr f, addr r) {
  int32_t j, p;
  for (j = 0; j < RADIX; ++j) f[j] = 0; //初始化各個子表
  for (p = data[0].next; p; p = data[p].next) {
    j = transchar(data[p].key[i]); //將關鍵字轉換為數字
    if (!f[j]) { //f[j]是空表,則f[j]指示第一個元素
      f[j] = p;
    } else {
      data[r[j]].next = p;
    }
    r[j] = p; //將p所指的節點插入第j個子表中
  }
}

//收集,按key[i]將f[0...radix - 1]所指各子表依次連接成一個靜態鏈表
void collect(listcell_t data[], addr f, addr r) {
  int32_t i;
  int32_t temp;
  for (i = 0; !f[i]; ++i); //找第一個非空子表,為求后續函數
  data[0].next = f[i];
  temp = r[i]; //r[0].next 指向第一個非空子表中的第一個節點
  while (i < RADIX - 1) {
    for (i = i + 1; i < RADIX - 1 && !f[i]; ++i); //查找下一個非空子表
    if (f[i]) {
      data[temp].next = f[i];
      temp = r[i];
    }
  }
  data[temp].next = 0; //temp指向最后一個非空子表中的最后一個節點
}

//基數排序,使得L成為按關鍵字非遞減的靜態鏈表,L.r[0]為頭節點
void radixsort(list_t *L) {
  int32_t i;
  addr f, r;
  //由低位到高位一次對各關鍵字進行分配和收集
  for (i = 0; i < (*L).keynumber; ++i) {
    distribute((*L).data, i, f, r); //第i次分配
    collect((*L).data, f, r); //第i次收集
    printf("the %d times collect result: ", i + 1);
    display_staticlist(*L);
  }
}

    result.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM