Advertisement

Help with Missile Command

Started by July 18, 2017 04:28 AM
43 comments, last by Glydion 7 years, 4 months ago

Out of curiousity, could you share the link to  "10 requisite games that you absolutely need to know and finish " that you mentioned in your first message? :P

Hey Marcus,

No problem!  Here's the link:

 

Advertisement

Thanks :)

You're most welcome, Marcus.

Whew, I'm beat.  I seriously need to learn linear algebra because not knowing it is really pounding me to the floor.

I've done what cmac suggested and subtracted the x's and y's from the "center" x and "mouse x" and the "center" y and "mouse y", respectively, and the program is now making my cannon fly away from the base hehe, not what I was expecting, so the cannon's center is probably not what I think it is.

I'm going to have to redo it again, but I'll be going to sleep now to pick it up tomorrow.  Goodnight.

lol :D

If you're having so much trouble with that, maybe you should consider trying a way for visualizing your numbers without any cannon or textures inbetween to add confusion, basically what am I doing now, image below.

Basically I have this 2 variables


mOriginX = { mClientWidth / 4.f };
mOriginY = { mClientHeight / 4.f };

that control what's the point I consider the origin, and then all my other functions draw based on that.

For example, I have a lineFromOrigin() function that wraps up the DrawLine() function from direct2D


void TrigClient::lineFromOrigin(const D2D1_POINT_2F& p, float strokeSize, D2D1_COLOR_F color)
{
	if (color.a != -1.f) {
		mBrush->SetColor(color);
	}
	mRenderTarger->DrawLine(D2D1::Point2F(mOriginX, mOriginY),
				D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), mBrush, strokeSize);
}

As you can see the line starts from wathever origin I decide to set and the origin also get added to my point coordinates to get the end-point of the line relative to the origin.

This also gives you the power to say that now holding right-mouse button sets mOriginX and mOriginY to the current mouse coordinate and since all your functions works based on that, you are effectively panning the entire view/Camera as you would do in any other drawing or 3d software.

 

And, if you can make it works with some circles and some lines, then you can make it work with a cannon as well :P

7mBlUrD.gif

 

I believe you need two vectors for this type of targeting system: The first, from the center of your cannon to the mouse hotspot position; and the second is the current orientation of the cannon.

Then you can use the dot product to find the angle between these two vectors and then use the cross product to find the direction to rotate.

Advertisement
28 minutes ago, Aerodactyl55 said:

I believe you need two vectors for this type of targeting system: The first, from the center of your cannon to the mouse hotspot position; and the second is the current orientation of the cannon.

Then you can use the dot product to find the angle between these two vectors and then use the cross product to find the direction to rotate.

given a single vector (x,y) andl 'h' = hypotenuse(sqrt(x*x+y*y)),

 I think the easiest thing you can do is either asin(h/y) or acos(h/x) or atan2(y,x), not sure if acos and asin conside the sign of the quadrant though.

@Aerodactyl55: can you explain a bit more about the cross product part? I thought it was only needed to get a vector perpendiculat to other 2 vectors in 3d space, how does it works/help with 2d?

11 minutes ago, MarcusAseth said:

@Aerodactyl55: can you explain a bit more about the cross product part? I thought it was only needed to get a vector perpendiculat to other 2 vectors in 3d space, how does it works/help with 2d?

The sign of the z-component (for 2D games) of that perpendicular vector will tell you the direction (left/right) to rotate.

Wow Marcus, that's one pretty big animated GIF lol.

That's so neat, I can only imagine being able to do that right now, so I still have a ways to go.

Yeah, you're right, I'm trying to figure out logic with so many objects and variables all at once, it's giving me a headache.

Hey Aerodactyl (my favorite Pokemon btw), yes I was looking up other posts about angles and yes I found it odd that i was trying to get an angle from only one vector, as angles are between two vectors *slaps forehead*.

I didn't factor in direction, which should be my other vector.

Ok, I'll design a small program specifically for this logic issue (with 2 vector lines, not one) and just use basic shapes when I get home. 

Gracias.

Good luck with it :)

I leave you the code from the image in the page before just in case helps, so you can see how I used the origin thing all over the place

Spoiler


#include "TrigClient.h"
#include <DirectXMath.h>
#include <iostream>
using std::cout; using std::endl;

#define rad(x) DirectX::XMConvertToRadians(x)
#define deg(x) DirectX::XMConvertToDegrees(x)

TrigClient::TrigClient(HINSTANCE instance, std::wstring caption, float width, float height)
	:D2DApp(instance, caption, width, height), mOriginX{ 0 }, mOriginY{ 0 }, mAngle{ 0 }, mAngleChange{ 70.f },
	mWaveBox{}, mMouse{ 0 }, mDashedLine{ nullptr }, mTriangleGeo{ nullptr }
{
}


TrigClient::~TrigClient()
{
	if (mDashedLine) { mDashedLine->Release(); }
	if (mTriangleGeo) { mTriangleGeo->Release(); }
}

bool TrigClient::Init()
{
	if (!D2DApp::Init())
	{
		return false;
	}
	//Additional initialization
	mOriginX = { mClientWidth / 2.f };
	mOriginY = { mClientHeight / 3.5f };

	//waveBox
	float waveBoxPadding = 50.f;
	float  waveBoxWidth = 350.f;
	float  waveBoxHeight = 250.f;
	mWaveBox.bottom = mClientHeight - waveBoxPadding;
	mWaveBox.top = mWaveBox.bottom - waveBoxHeight;
	mWaveBox.left = waveBoxPadding;
	mWaveBox.right = mWaveBox.left + waveBoxWidth;

	D2D1_STROKE_STYLE_PROPERTIES dashedLineProp{};
	dashedLineProp.startCap = D2D1_CAP_STYLE_FLAT;
	dashedLineProp.endCap = D2D1_CAP_STYLE_FLAT;
	dashedLineProp.dashCap = D2D1_CAP_STYLE_ROUND;
	dashedLineProp.lineJoin = D2D1_LINE_JOIN_MITER;
	dashedLineProp.miterLimit = 60.f;
	dashedLineProp.dashStyle = D2D1_DASH_STYLE_CUSTOM; //try DOT
	dashedLineProp.dashOffset = 3.3f; // might want to use this to animate the dashLine
	float dashes[] = { 6.0f, 6.0f, 6.0f };

	HRESULT hr = mFactory->CreateStrokeStyle(dashedLineProp, dashes, ARRAYSIZE(dashes), &mDashedLine);
	if (hr != S_OK) {
		MessageBoxW(mhWindow, L"failed to create dashed line", 0, 0);
		return false;
	}

	return true;
}

void TrigClient::Update(float dt)
{
	mAngle += mAngleChange*dt;

	float oneCircleTime = 360 / mAngleChange; //time required to complete 1 revolution, in seconds
	unsigned pointResolution = 30;
	float pointsPerSecond = 1 / pointResolution; //how often points are added, in seconds

	static float addPointTimer = 0;
	addPointTimer += dt;
	//evaluate every t | determines wave resolution
	if (addPointTimer >= pointsPerSecond)
	{
		//function to turn into a wave
		D2D1_POINT_2F newPoint = { mTimer.totalTime() ,cos(rad(mAngle)) };
		
		//add new point
		mWavePoints.push_back(newPoint);

		//remove old Points
		for (size_t i = 0; i < mWavePoints.size(); i++)
		{
			if (mTimer.totalTime() - mWavePoints.front().x >= oneCircleTime) {
				mWavePoints.pop_front();
			}
			else {
				break;
			}
		}

		addPointTimer = 0;
	}
}

void TrigClient::Draw()
{
	//background
	mRenderTarger->Clear(D2D1::ColorF(0.41f, 0.41f, 0.41f, 1.0f));
	makeGrid(25);

	//circle stuff
	float radius = 250.f;
	D2D1_POINT_2F point1 = D2D1::Point2F(radius * cos(rad(mAngle)), radius * sin(rad(mAngle)));
	circileFromOrigin(radius, 3.f, D2D1::ColorF(0.2f, 0.65f, 0.86f, 1.f));
	lineFromOrigin(point1, 2.f, D2D1::ColorF(0.46f, 0.76f, 0.86f, 1.f));
	drawPointFromOrigin(point1, 6.f, D2D1::ColorF(1.0f, 0.15f, 0.30f, 1.f));
	projectionX(point1);
	perpX(point1);
	triangleAreaDisplay(point1);

	//draw wave box
	drawWaveBox(cos(rad(mAngle)));
}

void TrigClient::drawWaveBox(const float point)
{
	//transparent box base
	mBrush->SetColor(D2D1::ColorF(0.4f, 0.4f, 0.4f, 0.65f));
	mRenderTarger->FillRectangle(mWaveBox, mBrush);
	//box outline
	mBrush->SetColor(D2D1::ColorF(0.9f, 0.9f, 0.0f, 0.45f));
	mRenderTarger->DrawRectangle(mWaveBox, mBrush);

	//horizontal line
	mBrush->SetColor(D2D1::ColorF(0.08f, 0.08f, 0.08f, 1.0f));
	float boxWidth = mWaveBox.right - mWaveBox.left;
	float boxHeight = mWaveBox.bottom - mWaveBox.top;
	float marks = 50;
	float linePaddingH = 20;
	float linePaddingV = 10;
	float lineBoundLeft = mWaveBox.left + linePaddingH;
	float lineBoundRight = mWaveBox.right - linePaddingH;
	float lineBoundBottom = mWaveBox.bottom - linePaddingV;
	float lineLength = lineBoundRight - lineBoundLeft;
	float intervalSpace = lineLength / marks;

	mRenderTarger->DrawLine(D2D1::Point2(lineBoundLeft, lineBoundBottom),
							D2D1::Point2(lineBoundRight, lineBoundBottom), mBrush, 1.f);
	//horizontal marks
	for (size_t i = 0; i <= marks; i++) {
		mRenderTarger->DrawLine(D2D1::Point2(lineBoundLeft + (intervalSpace*i), lineBoundBottom - 5),
								D2D1::Point2(lineBoundLeft + (intervalSpace*i), lineBoundBottom + 5), mBrush, 1.f);
	}

	//internal box
	float internalBoxTop = mWaveBox.top + (mWaveBox.bottom - lineBoundBottom) + linePaddingV;
	float internalBoxBottom = lineBoundBottom - linePaddingV;
	mBrush->SetColor(D2D1::ColorF(0.24f, 0.24f, 0.24f, 0.85f));
	mRenderTarger->FillRectangle(D2D1::RectF(lineBoundLeft, //left
											 internalBoxTop, //top
											 lineBoundRight, //right
											 internalBoxBottom),// bottom
								 mBrush);
	//draw wave
	float internalBoxMidY = internalBoxTop + ((internalBoxBottom - internalBoxTop) / 2);
	float oneCircleTime = 360 / mAngleChange;
	float graphHSpace = lineBoundRight - lineBoundLeft;
	float graphYSpace = internalBoxBottom - internalBoxTop;
	for (auto& point : mWavePoints)
	{
		float pointAge = mTimer.totalTime() - point.x;
		drawPoint(D2D1::Point2F(lineBoundLeft + ((graphHSpace / oneCircleTime) * pointAge),//X
								internalBoxMidY + (-point.y * graphYSpace / 2.05f))//Y
				  , 2.6f, D2D1::ColorF(-point.y, point.y, point.y, 0.85f));
	}
}

void TrigClient::projectionX(const D2D1_POINT_2F& p)
{
	mBrush->SetColor(D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
	mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), D2D1::Point2F(mOriginX + p.x, mOriginY), mBrush, 1.f, mDashedLine);
	drawPointFromOrigin(D2D1::Point2F(p.x, 0), 5.f, D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
}

void TrigClient::perpX(const D2D1_POINT_2F& p)
{
	mBrush->SetColor(D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
	mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), D2D1::Point2F(mOriginX, mOriginY - p.y), mBrush, 1.f, mDashedLine);
	drawPointFromOrigin(D2D1::Point2F(0, p.y), 5.f, D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
}

void TrigClient::triangleAreaDisplay(const D2D1_POINT_2F& p)
{
	//free previous triangle
	if (mTriangleGeo) { mTriangleGeo->Release(); }

	//create triangle path geo
	HRESULT hr = mFactory->CreatePathGeometry(&mTriangleGeo);
	if (hr != S_OK) {
		assert(hr == S_OK);
		MessageBoxW(mhWindow, L"failed to create triangle path geo", 0, 0);
	}

	ID2D1GeometrySink* pSink;
	D2D1_POINT_2F tringle[3] = {
								{ mOriginX + p.x,mOriginY},
								{ mOriginX + p.x , mOriginY - p.y},
								{ mOriginX, mOriginY }
	};

	mTriangleGeo->Open(&pSink);
	pSink->BeginFigure(D2D1::Point2F(mOriginX, mOriginY), D2D1_FIGURE_BEGIN_FILLED);
	//build shape here//
	pSink->AddLines(tringle, 3);
	////////////
	pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
	pSink->Close();
	pSink->Release();

	//draw shape
	float point = cos(rad(mAngle));
	mBrush->SetColor(D2D1::ColorF(-point, point, point, 0.7f));
	mRenderTarger->FillGeometry(mTriangleGeo, mBrush);
}

void TrigClient::makeGrid(float spacing)
{
	mBrush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
	//Major Horizontal and Vertical lines
	mRenderTarger->DrawLine(D2D1::Point2F(0.0f, mOriginY),
							D2D1::Point2F(mClientWidth, mOriginY),
							mBrush, 2.f);
	mRenderTarger->DrawLine(D2D1::Point2F(mOriginX, 0.0f),
							D2D1::Point2F(mOriginX, mClientHeight),
							mBrush, 2.f);

	//Vertical lines

	unsigned leftLines = (int)(mOriginX / spacing);
	unsigned righttLines = (int)((mClientWidth - mOriginX) / spacing);
	unsigned verticalLines = leftLines > righttLines ? leftLines : righttLines;

	for (size_t i = 1; i <= verticalLines; i++)
	{
		//left
		mRenderTarger->DrawLine(D2D1::Point2F(mOriginX - (i*spacing), 0.f),
								D2D1::Point2F(mOriginX - (i*spacing), mClientHeight),
								mBrush, 0.25f);
		//right
		mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + (i*spacing), 0.f),
								D2D1::Point2F(mOriginX + (i*spacing), mClientHeight),
								mBrush, 0.25f);
	}

	//Horizontal lines

	unsigned topLines = (int)(mOriginY / spacing);
	unsigned bottomtLines = (int)((mClientHeight - mOriginY) / spacing);
	unsigned horizontalLines = topLines > bottomtLines ? topLines : bottomtLines;
	for (size_t i = 1; i <= horizontalLines; i++)
	{
		//up
		mRenderTarger->DrawLine(D2D1::Point2F(0.f, mOriginY - (i*spacing)),
								D2D1::Point2F(mClientWidth, mOriginY - (i*spacing)),
								mBrush, 0.25f);
		//down
		mRenderTarger->DrawLine(D2D1::Point2F(0.f, mOriginY + (i*spacing)),
								D2D1::Point2F(mClientWidth, mOriginY + (i*spacing)),
								mBrush, 0.25f);
	}
}

void TrigClient::lineFromOrigin(const D2D1_POINT_2F& p, float strokeSize, const D2D1_COLOR_F& color)
{
	if (color.a != -1.f) {
		mBrush->SetColor(color);
	}
	mRenderTarger->DrawLine(D2D1::Point2F(mOriginX, mOriginY),
							D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), mBrush, strokeSize);
}

void TrigClient::circileFromOrigin(const float radius, float strokeSize, const D2D1_COLOR_F& color)
{
	if (color.a != -1.f) {
		mBrush->SetColor(color);
	}
	mRenderTarger->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(mOriginX, mOriginY), radius, radius),
							   mBrush, strokeSize);
}

void TrigClient::drawPoint(const D2D1_POINT_2F& p, float radius, const D2D1_COLOR_F& color)
{
	if (color.a != -1.f) {
		mBrush->SetColor(color);
	}
	mRenderTarger->FillEllipse(D2D1::Ellipse(D2D1::Point2F(p.x, p.y), radius, radius), mBrush);
}

void TrigClient::drawPointFromOrigin(const D2D1_POINT_2F& p, float radius, const D2D1_COLOR_F& color)
{
	if (color.a != -1.f) {
		mBrush->SetColor(color);
	}
	mRenderTarger->FillEllipse(D2D1::Ellipse(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), radius, radius),
							   mBrush);
}

 

 

This topic is closed to new replies.

Advertisement