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?
Help with Missile Command
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
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
My portfolio: https://www.artstation.com/artist/marcusaseth
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.
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?
My portfolio: https://www.artstation.com/artist/marcusaseth
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
#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);
}
My portfolio: https://www.artstation.com/artist/marcusaseth