info

2Dゲーム用の重力計算モジュール作った、google test試しに使ってみた

moveable.hh

#include <cmath>

#ifndef _MOVEABLE_H_
#define _MOVEABLE_H_


namespace moveable
{
	//いろいろな定数値、後でcommon.hに入れてもらう
	const float PI = static_cast<float>(atan(1.0) * 4);
	const float RAD = PI / 180;//HACK 30度 = 1/6ラジアン

	const float LEFT_HORIZON_ANGLE = PI;
	const float RIGHT_HORIZON_ANGLE = 0.0;
	const float RIGHT_JUMP_ANGLE = -((2/6) * PI);
	const float LEFT_JUMP_ANGLE = -((4/6) * PI);
	const float VERTICAL_JUMP_ANGLE = -((3/6) * PI);

	const float GLOBAL_INIT_GRAVITY = 2.0;


	//座標を表わすクラス
	class point
	{	
	public:
		float _x;
		float _y;

		point(): _x(0.0), _y(0.0) {}
		virtual ~point(){}

		inline point operator + (point &other)
		{
			point result;
			result._x = this->_x + other._x;
			result._y = this->_y + other._y;
			return result;
		}
	};


	//座標を動かしたいクラスにこれを継承させ仮想関数を定義させる、下のコンポジションさせたクラスが値を取得するために必要
	class moveable_mixin	{
	public:
		virtual void set_point(point) = 0;
		virtual point get_point() = 0;
		virtual bool is_ground_stick() = 0;
	};


	//座標を動かしたいクラスにコンポジションさせる
	//コンストラクタにMoveableMixinを継承させたクラスのthisポインタを入れること
	//加速度(set_acceleration)などを設定した後、座標と速度を更新するためにmoveメソッドを最後に呼ぶ
	class moveable
	{
	public:
		moveable(moveable_mixin *p) : _parent(p), _acceleration(), _velocity(), _gravity(GLOBAL_INIT_GRAVITY){}
		virtual ~moveable(){}
		
		void force_stop();
		void move();
		void add_acceleration(float acceleration, float angle);
		void set_const_velocity(float speed, float angle);
		void set_gravity(float g);


	private:
		moveable_mixin *_parent; 
		point _acceleration;
		point _velocity;
		float _gravity;
	};
}

#endif /*_MOVEABLE_H_*/

moveable.cc

#include "moveable.hh"

namespace moveable {

	//加速度と速度をゼロにして、動きを止める
	void moveable::force_stop()
	{
		_velocity._x = 0.0;
		_velocity._y = 0.0;
		_acceleration._x = 0.0;
		_acceleration._y = 0.0;
	}

	//加速度を速度に足し、速度を座標に足して動かす、重力がはたらいているならば考慮し、計算する
	void moveable::move()
	{
		_velocity._x += _acceleration._x;
		_velocity._y = (_parent->is_ground_stick() ? 0.0f : _velocity._y + _acceleration._y + _gravity);
		_parent->set_point(_parent->get_point() + _velocity);
	}

	//加速度と角度をもらって加速度ベクトルを表わす極座標に足す
	void moveable::add_acceleration(float acceleration, float angle)
	{
		this->_acceleration._x += acceleration * cos(angle);
		this->_acceleration._y += acceleration * sin(angle);
	}

	//加速度をゼロにして、速度のみをセットする、速度と角度をもらって速度ベクトルを表わす極座標に足す
	void moveable::set_const_velocity(float velocity, float angle)
	{
		force_stop();
		this->_velocity._x = velocity * cos(angle);
		this->_velocity._y = velocity * sin(angle);
	}

	//重力をセットする
	void moveable::set_gravity(float g)
	{
		_gravity = g;
	}
}

test.cc

#include <gtest/gtest.h>
#include "moveable.hh"


//test用ドライバークラス
class obj :public moveable::moveable_mixin
{
public:
	obj() {
		_moveable = new moveable::moveable(this);
	}
	virtual ~obj(){}

	moveable::point get_point()
	{
		return point;
	}
	void set_point(moveable::point p)
	{
		point = p;
	}

	bool is_ground_stick()
	{
		return ground_stick;
	}

	bool ground_stick;
	moveable::point point;
	moveable::moveable *_moveable;	
};

TEST(MoveableTest, Assert)
{
	obj testobj;
	
	//addAccelerationでの移動距離が合っているか、加速度がはたらくか
	testobj.ground_stick = false;
	testobj._moveable->set_gravity(0.0);
	testobj._moveable->add_acceleration(sqrt(8.0f),(moveable::PI / -4));
	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 2.0f);
	EXPECT_FLOAT_EQ(testobj.get_point()._y, -2.0f);

	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 6.0f);
	EXPECT_FLOAT_EQ(testobj.get_point()._y, -6.0f);


	//地面より下に落さないための処理がはたらくか
	testobj.point._x = 0;
	testobj.point._y = 0;
	testobj._moveable->force_stop();

	testobj.ground_stick = true;
	testobj._moveable->set_gravity(moveable::GLOBAL_INIT_GRAVITY);
	testobj._moveable->add_acceleration(sqrt(2.0f),(moveable::PI / -4));
	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 1.0f);
	EXPECT_FLOAT_EQ(testobj.get_point()._y, 0.0f);


	//setconstVelocityでの移動距離が合っているか
	testobj.point._x = 0;
	testobj.point._y = 0;
	testobj.ground_stick = false;
	testobj._moveable->set_gravity(0.0);

	testobj._moveable->set_const_velocity(sqrt(2.0f),(moveable::PI / -4));
	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 1.0f);
	EXPECT_FLOAT_EQ(testobj.get_point()._y, -1.0f);

	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 2.0f);
	EXPECT_FLOAT_EQ(testobj.get_point()._y, -2.0f);


	//重力がはたらくか
	testobj.point._x = 0;
	testobj.point._y = 0;
	testobj._moveable->force_stop();

	testobj.ground_stick = false;
	testobj._moveable->set_gravity(moveable::GLOBAL_INIT_GRAVITY);
	testobj._moveable->add_acceleration(sqrt(8.0f),(moveable::PI / -4));
	testobj._moveable->move();

	EXPECT_FLOAT_EQ(testobj.get_point()._x, 2.0f);
	EXPECT_NEAR(testobj.get_point()._y, 0, 1e-6f);
}

//int main(int argc, char **argv)
//{
//	testing::InitGoogleTest(&argc, argv);
//	RUN_ALL_TESTS();
//	return 0;
//}