Game rắn: Làm sao để cho con rắn đi xuyên tường và xuất hiện ở phía bên kia

chào mọi người
Em đang làm game snake. Có một chỗ em không fix được. Mong các anh hỗ trợ cho em nhé.
Em code trên cocos và dùng c++
Đây là lỗi của em.
Em mún cho con rắn nó đi xuyên tường và xuất hiện ở phía bên kia. Đây là code của em

void Snake::moveSnake(){

	snakeHead->warp();
	//cocos2d::log("rotation: %f, x: %f, y: %f", snakeHead->getRotation(), BODY_INTERVAL*sind(snakeHead->getRotation()), BODY_INTERVAL*cosd(snakeHead->getRotation()));
	auto move = MoveBy::create((float)moveSpeed / DIVIDER, Vec2(BODY_INTERVAL*sind(snakeHead->getRotation()), BODY_INTERVAL*cosd(snakeHead->getRotation())));
	auto end = CallFunc::create(CC_CALLBACK_0(Snake::moveEnd,this));

	isMoving = true;

	snakeHead->runAction(Sequence::create(move, end, NULL));

	for (int i = 1; i < size; i++){
		
		snakeBodyParts.at(i)->warp();

		auto move = MoveTo::create((float)moveSpeed / DIVIDER, snakeBodyParts.at(i - 1)->getPosition());
		snakeBodyParts.at(i)->runAction(move);

		auto rotate = RotateTo::create((float)moveSpeed / DIVIDER, (int)(snakeBodyParts.at(i - 1)->getRotation()) % 360);
		snakeBodyParts.at(i)->runAction(rotate);
	}
}

trong đó có hàm warp là hàm kiểm tra có đi ra ngoài cửa sổ game ko nếu có thì set position nó lại. Hàm này nó nằm ở file SnakePart.cpp

void SnakePart::warp(){
	if (this->getPositionX() < SCREEN_POSITION_LEFT){
		this->setPositionX(SCREEN_POSITION_RIGHT);
	}
	else if (this->getPositionX() > SCREEN_POSITION_RIGHT){
		this->setPositionX(SCREEN_POSITION_LEFT);
	}

	if (this->getPositionY() < SCREEN_POSITION_BOTTOM){
		this->setPositionY(SCREEN_POSITION_TOP);
	}
	else if (this->getPositionY() > SCREEN_POSITION_TOP){
		this->setPositionY(SCREEN_POSITION_BOTTOM);
	}
}

Mọi thứ tới đó đều ổn cho đến khi em chạy project thì nó bị như này ạ.

Con rắn phải bao gồm 3 hình tròn lúc mới vào game,nó vẫn có đủ ạ và vẫn đi từ trái sang phải
nhưng mấy phần thân của rắn nó di chuyển mọi nơi, trừ phần đầu ra ạ rồi mấy phần thân đó lại di chuyển rất nhanh và di chuyển lại chỗ cũ . Trong hình là cục thứ 3 nó di chuyển mất rồi sau đó nó quay lại chổ cũ. Tại giới hạn chỉ dc post 1 tấm hình nên em không post được tấm 2 3 để các anh hiểu rõ hơn.
Mong các anh giúp ạ

1 Like

Nếu không có vấn đề về logic, thì mình đoán là thread vẽ hình và thread position chạy song song. Do đó bạn cần phải thêm mutex lock/unlock khi thay đổi vị trí X,Y của các bộ phận.

5 Likes

cảm ơn bạn đã quan tâm tới topic của mình. Bạn có thể ví dụ một cái về mutex được không. Vì mình ko biết nó là gì ?

Khi lập trình đa luồng (multi-thread), bạn sẽ gặp tình huống 2 thread cùng truy xuất 1 giá trị (cụ thể ở đây là tọa độ của thân con rắn).
Giả sử bạn có 2 thread: drawSnakemoveSnake chạy song song, thread moveSnake thay đổi lần lượt đầu và thân rắn qua biên trái, đồng thời drawSnake nhảy vô lấy dữ liệu vị trí ngay lúc moveSnake mới chỉ xử lý vị trí của phần đầu. Như vậy dữ liệu vị trí đầu và thân không đồng bộ và dẫn tới tình trạng đầu 1 nơi, thân 1 nẻo.
Bạn có thể tìm kiếm từ khóa: Critical Section, multi thread, mutex để tìm các bài viết phù hợp.

5 Likes

Tại mình là newbie, nên đọc đến khái niệm này vẫn còn lạ lẫm và có hiểu thì mình ko biết áp dụng vào code của mình sao nữa. Bạn hãy giúp mình trả lời ở topic khác nhé. Mình đã code lại sử dụng setposition thay vì action. Cho nó dễ thôi ! Và gặp một bug mới, mình có post nó lên một topic khác. Mong bạn hãy sớm ghé qua và giải đáp hộ mình.
Đây là link: Game snake : snake không di chuyển .
Cảm ơn bạn đã quan tâm

Mình cũng không biết giải thích sao tốt hơn nữa.
Bạn có thể thử lại bằng cách đổi cái hàm này:

     for (int i = 1; i < size; i++){
		
		snakeBodyParts.at(i)->warp();

		auto move = MoveTo::create((float)moveSpeed / DIVIDER, snakeBodyParts.at(i - 1)->getPosition());
		snakeBodyParts.at(i)->runAction(move);

		auto rotate = RotateTo::create((float)moveSpeed / DIVIDER, (int)(snakeBodyParts.at(i - 1)->getRotation()) % 360);
		snakeBodyParts.at(i)->runAction(rotate);
	}

thành:

    for (int i = 1; i < size; i++){
		
		snakeBodyParts.at(i)->warp();
        }
       for (int i = 1; i < size; i++){
		auto move = MoveTo::create((float)moveSpeed / DIVIDER, snakeBodyParts.at(i - 1)->getPosition());
		snakeBodyParts.at(i)->runAction(move);

		auto rotate = RotateTo::create((float)moveSpeed / DIVIDER, (int)(snakeBodyParts.at(i - 1)->getRotation()) % 360);
		snakeBodyParts.at(i)->runAction(rotate);
	}

xem thử tình hình nhảy lung tung có cải thiện không. Nếu có thì nhận định trên của mình là đúng. Còn nếu không thì khả năng lỗi ở chỗ khác.

Còn việc bạn thay đổi hoàn toàn cấu trúc dẫn đến con rắn biến mất thì mình cũng chịu. Bạn thử đặt print debug xem?? Nếu không in được thông tin debug lên console thì có thể print thẳng lên màn hình game dưới dạng textBox luôn :smiley:

5 Likes

Mấy cái này ko dùng đến multithread đâu, nhất là các framework trên mobile nữa thì càng đơn giản.
Anh tin lỗi là do em đổi đơn vị ko tốt, do làm tròn dẫn đến so sánh đơn vị ko đúng. Tuy nhiên vì em cung cấp quá ít thông tin, anh ko biết SCREEN_POSITION_RIGHT và setPosition() của em là đơn vị gì nên anh ko giúp em dc thêm!

5 Likes

dạ đây :slight_smile:


Dạ em lấy đơn vị tính là pixel ạ
Anh không phiền có thêm tham khảo định nghĩa các Macro của em ạ.

#define SCREEN_WIDTH Globals::getVisibleSize().width
#define SCREEN_HEIGHT Globals::getVisibleSize().height

#define SCREEN_POSITION_LEFT 0
#define SCREEN_POSITION_RIGHT Globals::getVisibleSize().width
#define SCREEN_POSITION_TOP Globals::getVisibleSize().height
#define SCREEN_POSITION_BOTTOM 0

Mong anh giúp đỡ ạ.

Vẫn bị bạn ạ! Hic Mà vẫn cảm ơn bạn nhiều ,nhá

Cái dòng trên có đơn vị hơi loạn, 1 bên float 1 bên integer. Mà mấy cái code kiểm tra điều kiện chỉ cần lệch 0.001 là nó đã sai rồi. Để khắc phục em nên dùng 1 cái gọi là epsilon, em xem thêm ở đây:

5 Likes

mà anh ơi hình như hàm có parameter là float với Vec2 ạ: MoveBy::create(float,Vec2)

Nè em, Vec2 trong Cocos2d vẫn có thể sử dụng kiểu float, em nên dùng kiểu float thôi vì nó là chuẩn để so sánh trong game.

https://docs.cocos2d-x.org/api-ref/cplusplus/V3.1/d9/d7f/class_vec2.html

Để anh giải thích 1 chút cho em hiểu. Em update vận tốc theo 1 khoảng thời gian, gọi là tick. Vì cái tick này rất nhỏ, em update rất nhanh nên nhiều khi con rắn của em đã ở ngoài biên rồi mà em ko biết, nên code check sẽ bị sai.
Em nên đọc kỹ lại tài liệu hướng dẫn của em và chú ý đoạn anh nói, để xem em sai chỗ nào nhé. Chúc em thành công!

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?