30/09/2018, 18:49

[Help & Share] Trò chơi Con rắn săn mồi trên C++

Chào mọi người
Hiện em đang hoàn thiện một chương trìnhvề C++ là game Con rắn săn mồi. Về cơ bản em đã chạy được game nhưng em còn có rất nhiều thiếu sót, vì vậy em post lên đây mong được mọi người giúp đỡ để hoàn thiện chương trình đầu tiên của bản thân.

Em xin nêu ý tưởng cơ bản của trò chơi:

  1. Vẫn là con rắn ăn thức ăn trong một giới hạn màn hình ( không thể đâm vào tường- 1 thiếu sót)
  2. Em tạo con rắn theo danh sách liên kết, một nút là 1 bộ phận của con rắn
  3. Mỗi nút gồm vị trí toạ độ của nút và con trỏ chỉ vào phần thân phía sau ( nút phía sau)
  4. Cách thức di chuyển: in tất cả các nút >> chờ khoảng 1 giây để người dùng chỉ hướng đi của con rắn ( nếu ko chỉ hướng thì sau 1 giây nó vẫn di chuyển theo hướng cũ) >> cập nhật toạ độ các nút, kiểm tra có ăn được thức ăn hay không ( nếu ăn thì tạo nút mới) >> xoá toàn màn hình >> quay về bước 1 ( in tất cả các nút)
  5. Em tạo thêm một số chướng ngại vật rơi tự do để tăng độ khó cho game (hàm ghost)

Một số khúc mắc mong mọi người giúp đỡ:
1.Em dùng một số lượng lớn vòng for để tạo thời gian dùng lúc đợi người dùng ấn nút di chuyển con rắn. Nó khiến cho thời gian chờ này khác nhau tuỳ vào tốc độ máy tính khác nhau. Có cách nào khác để chờ không ạ?
2. Em tạo một hàm để di chuyển rắn là: xoá màn hình rồi in lại con rắn. Cái này phải nói là rất phi lập trình, có bác nào rảnh hướng dẫn em một thuật toán mới được không?
3. Mọi người chỉ em rõ về hàm GetAsyncKeyState(string key) được ko ạ?
4. Em đang muốn dùng một hàm random, nhưng chưa rõ. Nếu lấy trên mạng thì hàm sẽ scand(time(0)) + rand() để lấy random theo thời gian. Nhưng trong trò chơi của em nếu theo thời gian thì không đáp ứng được nhu cầu. Vì vậy em một hỏi có nào khác để tạo ramdom trong một khoảng nhất định nào đó hay không?

Đây là code của em, rất sơ sài và lủng củng. Mong được các bác tận tình chỉ bảo.

  • Code: https://ideone.com/6KTNAO
  • Test game (.exe): https://www.fshare.vn/file/H4SGJ5TFD9WJ
viết 21:04 ngày 30/09/2018
  1. trong <windows.h> có hàm Sleep(int milliseconds); có thể xài tạm. Ví dụ muốn game 60fps thì gọi Sleep(16); (1000/60 = 16). Ở đây game rắn ăn mồi này chắc ko cần fps… Để mô phỏng tốc độ trò chơi thì có thể chỉnh sửa ở chỗ Sleep này. Ví dụ tốc độ con rắn là 1 ô 1 giây thì cho Sleep(1000), tốc độ là 5 ô 1 giây thì Sleep(200).

  2. cách này là cách làm đúng rồi. Với game phức tạp hơn thì chỉ có cách clear screen rồi vẽ lại từ đầu. Console ko phải là môi trường thích hợp cho game nên mới gặp vấn đề.
    cách giải quyết với game rắn săn mồi trên console này là khi di chuyển, thay vì xóa màn hình thì chỉ xóa 1 ô ở đuôi con rắn (gotoxy tới đuôi con rắn rồi output 1 khoảng trắng), rồi vẽ 1 ô ở đầu con rắn (vị trí mà con rắn di chuyển kế tiếp).

  3. GetAsyncKeyState(key) bắt sự kiện key được nhấn tại thời điểm bất kì… ko biết chỉ gì hơn ở đây?

  4. gọi srand() 1 lần ngay sau dấu { ở main(), rồi xài rand() bình thường.
    random trong đoạn [a,b] là rand() % (b-a+1) + a;

làm game đừng làm trên console nữa. Làm 1 trò rắn săn mồi vậy là đủ rồi. Nhảy qua SDL đi: http://lazyfoo.net/tutorials/SDL/index.php

yoloh3 viết 20:56 ngày 30/09/2018

Thank you very much. Hi
Cho em hỏi thêm tí nữa:
Hàm rand() % (b-a+1) + a; em cũng biết rồi. Nhưng mà có nó vẫn có vấn đề.

  • Nếu ta dùng hàm rand() theo thời gian như em đã nói ở đầu topic thì giá trị trả về sẽ luôn là tăng dần theo thời gian
  • Nếu ko theo thời gian, thì hàm rand() sẽ luôn trả về 1giá trị mặc định nào đấy
viết 20:57 ngày 30/09/2018

“tăng” dần là sao?

rand() đúng là ko phải thực sự ngẫu nhiên, mà nó được tính theo công thức:

srand(int s):
  seed = s

rand():
  seed = (a*seed + b) % RAND_MAX
  return seed

trong đó a, b là 2 hằng số, được chọn làm sao để dãy số mà rand() tạo ra khác nhau đôi một thật dài.

Microsoft Research

Microsoft Research Lab - Redmond - Microsoft Research

At Microsoft, basic and applied research plays a vital role in breakthrough technological innovations that empower people to achieve more. The research tradition at Microsoft was formalized in 1991 with the founding of the Microsoft Research Redmond...


ví dụ 2 số ở đây là 1103515245 và 12345. Có cả tỷ tỷ cặp số nên mỗi compiler lại có thể xài cặp khác nhau.

như vậy số ngẫu nhiên mới sẽ phụ thuộc vào số ngẫu nhiên tạo ra liền trước nó. Vì vậy chỉ cần gọi srand(time(0)) 1 lần thôi. Vì nếu gọi srand(time(0)) trước mỗi lần gọi rand() thì seed lại được reset => sai.

với 1 seed bất kì sẽ tạo ra 1 dãy số “ngẫu nhiên”, số sau phụ thuộc số liền trước nó: s0, s1, s2, s3, … trong đó s1 phụ thuộc s0 (cụ thể là s1 = (a*s0 + b) % RAND_MAX), s2 phụ thuộc s1, v.v…

nếu đặt srand() trong hàm newFood() thì 2 số s1 s2 tạo ra khi gọi rand() dễ dàng tính được theo s0. Sau 1 khoảng thời gian nào đó, lại gọi srand() 1 lần nữa thì seed lại được reset lại thành s0 + t. 2 lần gọi rand() tiếp theo lại ra s1 + x, s2 + y trong đó x, y phụ thuộc t. Ta đoán là nó “tăng dần” ở đây.

nếu gọi srand() 1 lần ở trong main(), xóa srand() trong newFood đi thì mỗi lần gọi newFood() nó tạo s3 s4 s5 s6 v.v… ko phụ thuộc vào thời điểm gọi newFood() nữa, mà phụ thuộc vào thời điểm bắt đầu chương trình.

.
.
.
.
srand() ko phải gọi trong hàm newFood() mà gọi trong main()

int main()
{
   srand(time(0)); //1 lần duy nhất ở đây.

   //......
}
yoloh3 viết 21:03 ngày 30/09/2018

Hiểu rồi, cảm ơn nha.

Bài liên quan
0