社区讨论

物理引擎展示

灌水区参与者 5已保存回复 13

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
13 条
当前快照
1 份
快照标识符
@m2et101u
此快照首次捕获于
2024/10/18 22:07
去年
此快照最后确认于
2025/11/04 23:52
4 个月前
查看原帖
CPP
#include<iostream>
#include<time.h>
#include<windows.h>
#include<math.h>
#include<algorithm>
#include<list>
#include<map>
#include<unordered_map>
#include<cstring>
#include<typeinfo>
BITMAPINFO bmpinfo;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
union Object {
	#define _UNION_CONVER(type) type _##type;\
								type& operator=(const type &right) {_##type = right;};\
								operator type(){return _##type;}
	using _string = std::string;
	_UNION_CONVER(int);
	_UNION_CONVER(short);
	_UNION_CONVER(_string);
	_UNION_CONVER(long);
	_UNION_CONVER(float);
	_UNION_CONVER(double);
	_UNION_CONVER(bool);
	Object operator=(const Object &a) {
		#define _UNION_PUT(type) _##type = a._##type 
		_UNION_PUT(int);
		_UNION_PUT(short);
		_UNION_PUT(_string);
		_UNION_PUT(long);
		_UNION_PUT(float);
		_UNION_PUT(double);
		_UNION_PUT(bool);
		return a;
	}
	size_t operator()(const Object &a) {
		return a._int;
	}
	~Object(){};
	Object(){};
	Object(const Object &a) {
		*this = a;
	}
	bool operator==(const Object &a)
    {
		#define _UNION_COMPARE(a, type) (typeid(a) == typeid(type) && this -> _##type == a._##type) 
    	if(typeid(a) == typeid(this)) {
    		return _UNION_COMPARE(a, int) ||
				    _UNION_COMPARE(a, short) ||
				   	_UNION_COMPARE(a, _string) ||
				   	_UNION_COMPARE(a, long) ||
				   	_UNION_COMPARE(a, float) ||
				   	_UNION_COMPARE(a, double) ||
				   	_UNION_COMPARE(a, bool); 
		} else {
			return false;
		}
    }
	#undef _UNION_CONVER
};
class Vector2 {
	public:
		double x;
		double y;
		Vector2(): x(0), y(0) {}
		Vector2(double a, double b): x(a), y(b) {}
		Vector2 operator+(Vector2 a) {
			return Vector2(x + a.x, y + a.y);
		}
		Vector2 operator-(Vector2 a) {
			return Vector2(x - a.x, y - a.y);
		}
		Vector2 operator*(double a) {
			return Vector2(x * a, y * a);
		}
		double Module() {
			return sqrt(x * x + y * y);
		}
		Vector2 Normalize() {
			return *this * (1 / (*this).Module());
		}
		Vector2 operator+=(Vector2 a) {
			x += a.x, y += a.y;
			return Vector2(x, y);
		}
		Vector2 operator-=(Vector2 a) {
			x -= a.x, y -= a.y;
			return Vector2(x, y);
		}
		Vector2 operator*=(double a) {
			x *= a, y *= a;
			return Vector2(x, y);
		}
		bool operator==(Vector2 a) {
			return x == a.x && y == a.y;
		}
		bool operator!=(Vector2 a) {
			return x != a.x || y != a.y;
		}
		std::string ToString() {
			return '(' + std::to_string(x) + ',' + std::to_string(y) + ')';
		}
};
double Cross(Vector2 a, Vector2 b) {
	return a.x * b.y - a.y * b.x;
}
double Dot(Vector2 a, Vector2 b) {
	return a.x * b.x + a.y * b.y;
}
typedef Vector2 Vector;
enum class EntityType{
	PLAYER,
	CAMERA
};
bool Equal(double a, double b) {
	if(fabs(a - b) <= 1e-6) {
		return true;
	}
	return false;
}
class Entity{
	public:
		Vector position = Vector(0, 0);
		Vector velocity = Vector(0, 0);
		bool Invisible = false;
		double Health;
		std::string custom_name;
		EntityType type;
		std::unordered_map<std::string, Object> tag;
};
typedef __time64_t Time;
double tickTime = 0;
Time GetTime() {
	FILETIME t;
	GetSystemTimeAsFileTime(&t);
	return (Time)t.dwHighDateTime << 32 | t.dwLowDateTime;
}
template<typename T1> class DyadicArray {
	public:
		int width;
		T1 a[100000000];
		bool set(int x, int y, int value) {
			if(x + y * width >= 100000000) return false;
			if(x >= width) return false;
			if(x < 0 || y < 0) return false;
			a[x + y * width] = value;
			return true;
		}
		bool Clear() {
			memset(a, 0, sizeof(a));
			return true;
		}
		T1 get(int x, int y) {
			return a[x + y * width];
		}
};
typedef DyadicArray<COLORREF> ColorMap;
bool Segment(ColorMap &a, Vector start, Vector end, COLORREF color) {
	bool result = false;
	double k = (start.y - end.y) / (start.x - end.x);
	if(fabs(k) <= 1) {
		if(start.x > end.x) std::swap(start, end);
		for(int x = start.x; x <= end.x && start.x != end.x; ++x) {
			result |= a.set(x, (int)(k * (x - start.x) + start.y), color);
		}
	} else {
		if(start.y > end.y) std::swap(start, end);
		k = (start.x - end.x) / (start.y - end.y);
		for(int y = start.y; y <= end.y && start.y != end.y; ++y) {
			result |= a.set((int)(k * (y - start.y) + start.x), y, color);
		}
	}
	return result;
}
ColorMap cmap;
std::list<Entity> entity;
std::list<std::pair<Vector, Vector> > wall;
typedef std::list<Entity>::iterator ExistentEntity;
bool Remove(std::list<Entity> &a, ExistentEntity entity) {
	if(entity == a.end()) {
		return false;
	}
	a.erase(entity);
	return true;
}
ExistentEntity Spawn(std::list<Entity> &a, EntityType entity_type, Vector position, std::unordered_map<std::string, Object> tag = std::unordered_map<std::string, Object>{}) {
	Entity temp_entity;
	temp_entity.position = position;
	temp_entity.velocity = Vector(0, 0);
	temp_entity.type = entity_type;
	for(std::unordered_map<std::string, Object>::iterator i = tag.begin(); i != tag.end(); ++i) {
		temp_entity.tag.insert(*i);
	}
	a.push_back(temp_entity);
	return prev(a.end());
}
ExistentEntity player, camera;
std::unordered_map<DWORD, bool> keyDown;
bool PaintScreen(HWND hwnd) {
	cmap.Clear();
	RECT rect;                  
	GetWindowRect(hwnd, &rect);
	COORD size;
	size.X = rect.right - rect.left;
	size.Y = rect.bottom - rect.top;
	cmap.width = size.X;
	bmpinfo.bmiHeader.biWidth = size.X;
	bmpinfo.bmiHeader.biHeight = size.Y;
	HDC hdc = GetDC(hwnd);
	HDC hdcmem = CreateCompatibleDC(hdc);
	HBITMAP hbmpmem = CreateCompatibleBitmap(hdc, size.X, size.Y);
	for(std::list<Entity>::iterator temp_entity = entity.begin(); temp_entity != entity.end(); ++temp_entity) {
		switch(temp_entity -> type) {
			case(EntityType::PLAYER): {
				Vector position = (*temp_entity).position, temp_array[4] = {Vector(1, 1), Vector(1, -1), Vector(-1, -1), Vector(-1, 1)};
				for(int j = 0; j < 4; ++j) {
					Segment(cmap, (position - (*camera).position + temp_array[j] * 16) + Vector(size.X / 2, size.Y / 2), (position - (*camera).position + temp_array[(j + 1) % 4] * 16) + Vector(size.X / 2, size.Y / 2), 0xFFFFFF);
				}
				break;
			}
			default: {
				break;
			}
		}
	}
	for(std::list<std::pair<Vector, Vector> >::iterator temp_wall = wall.begin(); temp_wall != wall.end(); ++temp_wall) {
		Segment(cmap, (temp_wall -> first - (*camera).position) + Vector(size.X / 2, size.Y / 2), (temp_wall -> second - (*camera).position) + Vector(size.X / 2, size.Y / 2), 0xFFFFFF);
	}
	SelectObject(hdcmem, hbmpmem);
	SetDIBits(hdcmem, hbmpmem, 0, size.X, cmap.a, &bmpinfo, DIB_RGB_COLORS);
	BitBlt(hdc, 0, 0, size.X, size.Y, hdcmem, 0, 0, SRCCOPY);
	return true;
}
Time lastCalculate = GetTime();
bool Calculate() {
	Time thisCalculate = GetTime();
	Time subTime = 2 / tickTime;
	while(thisCalculate - lastCalculate > subTime) {
		if(keyDown['W'] && player -> tag["on_ground"]._bool) {
			player -> velocity.y += 2 * subTime * tickTime;
		}
		if(keyDown['S']) {
			player -> velocity.y -= 0.2 * subTime * tickTime;
		}
		if(keyDown['A']) {
			player -> velocity.x -= 0.1 * subTime * tickTime;
		}
		if(keyDown['D']) {
			player -> velocity.x += 0.1 * subTime * tickTime;
		}
		player -> velocity.y -= 0.1 * subTime * tickTime;
		player -> position += player -> velocity * subTime * tickTime;
		camera -> velocity = (player -> position - camera -> position) * 0.05;
		camera -> position += camera -> velocity * subTime * tickTime;
//		player -> velocity *= exp(log(0.99) * subTime * tickTime);
		player -> tag["on_ground"] = false;
		for(std::list<std::pair<Vector, Vector> >::iterator temp_wall = wall.begin(); temp_wall != wall.end(); ++temp_wall) {
			Vector a = temp_wall -> first, b = temp_wall -> second, ab = b - a;
			Vector temp_array[5] = {Vector(0, 0), Vector(1, 1), Vector(1, -1), Vector(-1, -1), Vector(-1, 1)};
			Vector majorVector = Vector(0, 0);
			Vector maxVector = Vector(0, 0);
			for(int i = 0; i < 5; ++i) {
				Vector p = player -> position + temp_array[i] * 16;
				Vector ap = p - a;
				Vector ph = ab * ((Dot(ap, ab)) / (Dot(ab, ab))) - ap;
				if(i == 0) {
					majorVector = ph;
				} else {
					if(Dot(ph, majorVector) <= 0) {
						if(maxVector.Module() < ph.Module()) {
							maxVector = ph;
						}
					}
				}
			}
			player -> position += maxVector * 1;
			if(maxVector != Vector(0, 0)) {
				player -> tag["on_ground"] = Dot(maxVector, Vector(0, 1)) > 0 && !(Equal(Dot(maxVector, Vector(0, 1)), 0));
				Vector temp_vector = ab * (Dot(player -> velocity, ab) / Dot(ab, ab));
				player -> velocity = temp_vector + (player -> velocity - temp_vector) * (-(player -> tag["elasticity"]._double));
			}
		}
		lastCalculate += subTime;
	}
	return true;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
	switch(Message) {
		case WM_KEYDOWN: {
			keyDown[wParam] = true;
			break;
		}
		case WM_KEYUP: {
			keyDown[wParam] = false;
			break;
		}
		case WM_MOUSEMOVE: {
			break;
		}
		case WM_DESTROY: {
			PostQuitMessage(0);
			exit(0);
			break;
		}
		default: {
			return DefWindowProc(hwnd, Message, wParam, lParam);
		}
	}
	return 0;
}
bool CreateWall(Vector a, Vector b) {
	wall.push_back(std::make_pair(a, b));
	return true;
}
void Initialize() {
	tickTime = 1e-5;
	#define sin(x) sin((x) * 3.1415926 / 180)
	#define cos(x) cos((x) * 3.1415926 / 180)
	for(int i = 0; i < 90; ++i) {
		CreateWall(Vector(cos(i) * 100 + 100, sin(i) * 100 + 100), Vector(cos(i + 1) * 100 + 100, sin(i + 1) * 100 + 100));
	}
	CreateWall(Vector(100, 200), Vector(-100, 200));
	for(int i = 90; i < 180; ++i) {
		CreateWall(Vector(cos(i) * 100 - 100, sin(i) * 100 + 100), Vector(cos(i + 1) * 100 - 100, sin(i + 1) * 100 + 100));
	}
	CreateWall(Vector(200, 100), Vector(200, -100));
	for(int i = 180; i < 270; ++i) {
		CreateWall(Vector(cos(i) * 100 - 100, sin(i) * 100 - 100), Vector(cos(i + 1) * 100 - 100, sin(i + 1) * 100 - 100));
	}
	CreateWall(Vector(100, -200), Vector(-100, -200));
	for(int i = 270 ;i < 360; ++i) {
		CreateWall(Vector(cos(i) * 100 + 100, sin(i) * 100 - 100), Vector(cos(i + 1) * 100 + 100, sin(i + 1) * 100 - 100));
	}
	CreateWall(Vector(-200, 100), Vector(-200, -100));
	player = Spawn(entity, EntityType::PLAYER, Vector(0, 0));
	player -> tag["elasticity"] = double(1);
	camera = Spawn(entity, EntityType::CAMERA, Vector(0, 0));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	ShowWindow(GetConsoleWindow(), HIDE_WINDOW);
	bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmpinfo.bmiHeader.biWidth = 100;
	bmpinfo.bmiHeader.biHeight = 100;
	bmpinfo.bmiHeader.biPlanes = 1;
	bmpinfo.bmiHeader.biBitCount = 32;
	bmpinfo.bmiHeader.biCompression = BI_RGB;
	bmpinfo.bmiHeader.biSizeImage = 0;
	bmpinfo.bmiHeader.biXPelsPerMeter = 3000;
	bmpinfo.bmiHeader.biYPelsPerMeter = 3000;
	bmpinfo.bmiHeader.biClrUsed = 0;
	bmpinfo.bmiHeader.biClrImportant = 0;

	WNDCLASSEX wc;
	HWND hwnd;
	MSG msg;
	memset(&wc,0,sizeof(wc));
	wc.cbSize		 = sizeof(WNDCLASSEX);
	wc.lpfnWndProc	 = WndProc; /* insert window procedure function here */
	wc.hInstance	 = hInstance;
	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszClassName = "WindowClass";
	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION); /* use "A" as icon name when you want to use the project icon */
	wc.hIconSm		 = LoadIcon(NULL, IDI_APPLICATION); /* as above */

	if(!RegisterClassEx(&wc)) {
		MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
		return 0;
	}

	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,640,480,NULL,NULL,hInstance,NULL);
	if(hwnd == NULL) {
		MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
		return 0;
	}
	Initialize();
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != -1) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		Calculate();
		PaintScreen(hwnd);
		Sleep(1);
	}
	return msg.wParam;
}
RT,花了点时间弄了个小玩意(
运行得在编译选项加上-lgdi32
函数Initialize()内可以修改玩家弹性(默认为1)(为了做机械能守恒弄的)

回复

13 条回复,欢迎继续交流。

正在加载回复...