|
I separate all of my C++/CLI code into two solutions; one in 2010 and one in 2008....
|
|
|
|
|
I'm not sure how to go about this. What to use to draw the snake to the screen and how to get it to animate properly like grow in size when it collects an item or just moving around the screen. I was told not to use a Picture box but to use Panels and no timers.
http://www.youtube.com/watch?v=s2tlk1LpWjI&feature=related
Maybe start off more simple like in the vid the snake just grows and the entire snake body doesn't move.
Thanks in advance.
modified on Friday, March 25, 2011 8:38 PM
|
|
|
|
|
Well, what's your best guess at how to accomplish this?
Most likely it has something to do with what's been taught most recently. What kinds of graphics features have been gone over?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
hmm my best guess would be to paint the snake onto the screen using some onpaint method which I don't know which one to use. And how to update it so it can be animated. I don't know much about Brushes or graphics in .net. But I did use owner drawn tool tips and menues.
I tried this and updated it using a timer and "this->Invalidate();" but it didn't do what I wanted.
virtual void OnPaint(PaintEventArgs^ e) override
{
}
|
|
|
|
|
Personally, I would create segments of the snake out of small panel objects that have a solid foreground color.
Then, to move the snake, simply move the panel that's at the rear of the snake to the front of the snake.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
 Hi,
So far I created a Snake_Part class. When the Form1 class is first created is calls the Make_Snake Function which creates 4 Snake_Part objects which are added to the list.
How do I move the last panel to the front. I'm using a list to store the Snake_Part instances. A timer will be used to move the snake. I need to some how find the last/first elements in the list and then move them acordingly.
#include "stdafx.h"
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;
public ref class Snake_Part
{
public:
Panel^ panel;
Snake_Part( Form ^ form )
{
panel = gcnew Panel();
panel->BackColor = Color::Blue;
panel->Width = 20; panel->Height = 20;
form->Controls->Add(panel);
}
};
public ref class Form1 : public Form
{
public:
List<Snake_Part^>^ Parts;
int length;
Timer^ Timer1;
Form1()
{
Parts = gcnew List<Snake_Part^>();
Timer1 = gcnew Timer();
Timer1->Interval = 2000;
Timer1->Start();
Timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
Make_Snake();
}
void Make_Snake()
{
double clr = 255;
double dclr = 128 / 2;
for(int I = 0; I <= 3; I++)
{
Snake_Part^ p = gcnew Snake_Part(this);
p->panel->BackColor = Color::FromArgb(0,0,clr);
Parts->Add(p);
clr -= dclr;
}
for each (Snake_Part^ p in Parts)
{
length += p->panel->Width + 2;
p->panel->Left = length;
}
}
void move_snake()
{
}
System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{
move_snake();
}
};
[STAThread]
int main()
{
Application::Run(gcnew Form1());
}
Thanks
|
|
|
|
|
A couple of suggestions. You might want to use a Queue to store the snake segments. That makes it easy to retrieve the last segment and push it onto the front. But a List will work too.
You'll need a value that determines what direction the snake is moving in. Maybe two values, an X and Y value. These should be integers so that they can store 1, 0, or -1.
From there, you can calculate where to position the panel, based upon the head segment's X and Y values, multiplied by the movement indicator values.
The flow would be as follows:
Retrieve the last segment.
Store it in the Head segment holder variable.
Push it onto the front of the snake.
Calculate the new head position.
Position the Head segment according to the new position.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
 Thanks for the helpful suggestions. I got it to move the snake right fine but I need help with some of the coding to get it to move properly in the other directions. I'm curently trying to move the snake downwards but I'm stuck. Thanks.
#include "stdafx.h"
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;
public ref class snake_segment
{
public:
Panel^ panel;
snake_segment( Form ^ form )
{
panel = gcnew Panel();
panel->BackColor = Color::Blue;
panel->Width = 20; panel->Height = 20;
form->Controls->Add(panel);
}
};
public ref class Form1 : public Form
{
public:
List<snake_segment^>^ segments;
int l;
int size;
int last;
int x, y;
int x2,y2;
Timer^ Timer1;
bool game_started;
Form1()
{
segments = gcnew List<snake_segment^>();
Timer1 = gcnew Timer();
Timer1->Interval = 2000;
Timer1->Start();
Timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &Form1::Form_KeyDown);
Make_Snake();
}
void Make_Snake()
{
double clr = 255;
double dclr = 128 / 2;
for(int I = 0; I <= 3; I++)
{
snake_segment^ s = gcnew snake_segment(this);
s->panel->BackColor = Color::FromArgb(0,0,clr);
segments->Add(s);
clr -= dclr;
}
for each (snake_segment^ s in segments)
{
l += s->panel->Width + 2;
s->panel->Left = l;
}
}
void get_size_of_snake()
{
size=0;
for each (snake_segment^ s in segments)
{
size++;
}
}
void head_position()
{
x = segments[size-1]->panel->Left;
y = segments[size-1]->panel->Top;
}
void move_snake()
{
if(x2 ==1){segments[last]->panel->Left = x + segments[last]->panel->Width + 2;}
if(y2 == -1){segments[last]->panel->Left = x;segments[last]->panel->Top = x;}
x = segments[last]->panel->Left;
y = segments[last]->panel->Top;
last++;
if(last >= size){last=0;}
}
System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{
get_size_of_snake();
if(!game_started){head_position();game_started=true;}
move_snake();
}
System::Void Form_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
if(e->KeyCode == Keys::Down){y2 = -1;}
if(e->KeyCode == Keys::Up){y2 = 1;}
if(e->KeyCode == Keys::Left){x2 = -1;}
if(e->KeyCode == Keys::Right){x2 = 1;}
}
};
[STAThread]
int main()
{
Application::Run(gcnew Form1());
}
|
|
|
|
|
I think you have the values for y2 reversed in the Key handler.
If you want the snake to move down, you should be incrementing y2 , and decrementing it for up.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
The snake automaticaly moves once the right key is pressed. It sorta works but not sure on how to code it for it moving downwords.
Here is the move_snake function;
void move_snake()
{
if(x2 ==1)
{
segments[last]->panel->Left = x + segments[last]->panel->Width + 2;
x = segments[last]->panel->Left;
y = segments[last]->panel->Top;
last++;
if(last >= size){last=0;}
}
if(y2 == -1)
{
segments[last]->panel->Top = y + segments[last]->panel->Height + 2;
segments[last]->panel->Left = x;
x = segments[last]->panel->Left;
y = segments[last]->panel->Top;
last++;
if(last >= size){last=0;}
}
}
Would you be able to help with the code. It would be much aprecieated. Thanks.
|
|
|
|
|
I think the problem might be that you're not keeping track of which panel is at the head of the snake, since movement is referenced against the head panel.
The code might go something like this: ( I have not tested this code. It might need modification. )
if ( y2 == -1 )
{
segments[last]->panel->Top = y + segments[head]->panel->Top + 2;
segments[last]->panel->Left = segments[head]->panel->Left;
head = last;
last++;
if ( last >= size )
{
last = 0;
}
}
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
You are correct, that's what the problem was. The snake is now moving in all directions. Thanks for helping me out. 
|
|
|
|
|
One last thing. I got the collision function working 99% but there's a small glitch where if
the head collides with the tail the collision function doesn't catch it and the snake keeps moving.
The collision function.
void check_for_collision()
{
for(int Tail = 0; Tail <= (size-1); Tail++)
{
for(int I = 0;I <= (size-1); I++)
{
if(I != head){segments[I]->panel->BackColor= Color::Blue;} else
{
segments[head]->panel->BackColor= Color::Yellow;
}
if(head!= Tail && segments[head]->panel->Left == segments[Tail]->panel->Left && segments[head]->panel->Top == segments[Tail]->panel->Top)
{
segments[head]->panel->BackColor= Color::Red;
Timer1->Stop();
}
}
}
}
Entire code.
#include "stdafx.h"
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;
public ref class snake_segment
{
public:
Panel^ panel;
snake_segment( Form ^ form )
{
panel = gcnew Panel();
panel->Width = 20; panel->Height = 20;
form->Controls->Add(panel);
}
};
public ref class Form1 : public Form
{
public:
List<snake_segment^>^ segments;
int l;
int size;
int tail;
int head;
int x, y;
int direction;
Timer^ Timer1;
bool game_started;
Form1()
{
segments = gcnew List<snake_segment^>();
Timer1 = gcnew Timer();
Timer1->Interval = 500;
Timer1->Start();
Timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &Form1::Form_KeyDown);
Make_Snake();
}
void Make_Snake()
{
for(int I = 0; I <= 5; I++)
{
snake_segment^ s = gcnew snake_segment(this);
s->panel->BackColor = Color::FromArgb(0,0,255);
segments->Add(s);
}
for each (snake_segment^ s in segments)
{
l += s->panel->Width + 2;
s->panel->Left = l;
}
get_size_of_snake();
segments[size-1]->panel->BackColor= Color::Yellow;
}
void get_size_of_snake()
{
size=0;
for each (snake_segment^ s in segments)
{
size++;
}
head=size-1;
}
void head_position()
{
x = segments[size-1]->panel->Left;
y = segments[size-1]->panel->Top;
}
void move_snake()
{
if(direction==1)
{
segments[tail]->panel->Location = Drawing::Point(x - 20 - 2,y);
head = tail;
x = segments[head]->panel->Left;
y = segments[head]->panel->Top;
tail++;
if(tail >= size){tail=0;}
}
if(direction==-1)
{
segments[tail]->panel->Location = Drawing::Point(x + 20 + 2,y);
head = tail;
x = segments[head]->panel->Left;
y = segments[head]->panel->Top;
tail++;
if(tail >= size){tail=0;}
}
if(direction==2)
{
segments[tail]->panel->Location = Drawing::Point(x,y - 20 - 2);
head = tail;
x = segments[head]->panel->Left;
y = segments[head]->panel->Top;
tail++;
if(tail >= size){tail=0;}
}
if(direction==-2)
{
segments[tail]->panel->Location = Drawing::Point(x,y + 20 + 2);
head = tail;
x = segments[head]->panel->Left;
y = segments[head]->panel->Top;
tail++;
if(tail >= size){tail=0;}
}
}
void check_for_collision()
{
for(int Tail = 0; Tail <= (size-1); Tail++)
{
for(int I = 0;I <= (size-1); I++)
{
if(I != head){segments[I]->panel->BackColor= Color::Blue;} else
{
segments[head]->panel->BackColor= Color::Yellow;
}
if(head!= Tail && segments[head]->panel->Left == segments[Tail]->panel->Left && segments[head]->panel->Top == segments[Tail]->panel->Top)
{
segments[head]->panel->BackColor= Color::Red;
Timer1->Stop();
}
}
}
}
System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{
if(!game_started){head_position();game_started=true;}
move_snake();
check_for_collision();
}
System::Void Form_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
if(e->KeyCode == Keys::Left){direction=1;}
if(e->KeyCode == Keys::Right){direction=-1;}
if(e->KeyCode == Keys::Up){direction=2;}
if(e->KeyCode == Keys::Down){direction=-2;}
if(e->KeyCode == Keys::Space)
{
snake_segment^ s = gcnew snake_segment(this);
segments->Insert(tail,s);
head = tail;
segments[tail]->panel->Location = Drawing::Point(x + segments[head]->panel->Width + 2,y);
x = segments[head]->panel->Left;
y = segments[head]->panel->Top;
tail++;
get_size_of_snake();
if(tail >= size){tail=0;}
}
}
};
[STAThread]
int main()
{
Application::Run(gcnew Form1());
}
Thanks.
|
|
|
|
|
I think you should simplify the collision function. I don't think you need two loops.
If you want to check whether the head is colliding with any of the other segments, then just do:
for (int ThisSegment = 0; ThisSegment < (size-1); ThisSegment ++ )
{
if ( ThisSegment == head ) continue;
if ( segments[ThisSegment]->panel->Left == segments[head]->panel->Left &&
segments[ThisSegment]->panel->Top == segments[head]->panel->Top )
{
Timer->Stop();
}
}
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Thanks. Thats much simpler code then what I had.
|
|
|
|
|
Hi Richard. I was wondering if you would be able to help me with a bit of code. I posted it here. Thank You.
[Algorthm][^]
|
|
|
|
|
I had MFC dll which exposes some clases. I would like to load this dll dynamically.
hResult = LoadLibrary(_T("c:\test.dll));
if (0 != hResult)
{
_InitSomeDLLFun = (InitSomeDLL)::GetProcAddress(hResult, "InitSomeDLL");
// always Undefind value is returned by GetProcAddress
if(_InitSomeDLL)
{
_InitSomeDLLFun();
}
err = GetLastError();
}
Please advice
|
|
|
|
|
What error is returned? Have you checked that InitSomeDLL is exported by your DLL and is not a mangled C++ name?
I must get a clever new signature for 2011.
|
|
|
|
|
The LoadLibrary() call was sucessfull, but
GetProcAddress() always returns <undefind value="">
the dlls are unmanaged dlls.
Please advice
|
|
|
|
|
Very interesting, but you didn't answer my questions.
I must get a clever new signature for 2011.
|
|
|
|
|
GetLastError() after the GetProcAddress returnts error code: 127
|
|
|
|
|
Did you bother to look up error code 127 to see what it indicates? I guess not; see here[^] for more information. Now you know what's wrong you can probably make a start at fixing it.
I must get a clever new signature for 2011.
|
|
|
|
|
Hi,
I'm currently making a simple game. Pressing the down arrow places a box on the form. Pressing up shoots missiles(blue boxes) and creates multiple instances of m1 which is part of the missle class.
What I want to do is change the color of each missle as it collides with the red box. So far only the last missile changes color. The other instances of the missle class get ignored.
#include "stdafx.h"
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
public ref class object
{
public:
PictureBox^ Box3;
object( Form ^ form )
{
Box3 = gcnew PictureBox();
Box3->Left = 150;
Box3->Top = 50;
Box3->Width = 100;
Box3->Height = 100;
Box3->BackColor = System::Drawing::Color::Red;
form->Controls->Add(Box3);
}
};
public ref class missile
{
public:
PictureBox^ Box1;
Timer^ Timer1;
missile( Form ^ form )
{
Timer1 = gcnew Timer;
Timer1->Interval = 1;
Timer1->Start();
Box1 = gcnew PictureBox();
Box1->Left = 150;
Box1->Top = 240;
Box1->Width = 10;
Box1->Height = 10;
Box1->BackColor = System::Drawing::Color::Blue;
form->Controls->Add(Box1);
Timer1->Tick += gcnew System::EventHandler(this, &missile::timer1_Tick);
}
System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{
Box1->Top -= 1;
}
};
public ref class Form1 : public Form
{
public:
PictureBox^ Box2;
missile^ m1;
object^ o1;
Timer^ Timer3;
bool x;
Form1()
{
x=false;
Timer3 = gcnew Timer();
Timer3->Interval = 1;
Timer3->Start();
Box2 = gcnew PictureBox();
Box2->BackColor = Color::Blue;
Box2->Top = 240;
Box2->Left = (this->Width / 2) - 40;
Box2->Width = 40;
Box2->Height = 10;
this->Controls->Add(Box2);
this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &Form1::Form_KeyDown);
Timer3->Tick += gcnew System::EventHandler(this, &Form1::timer3_Tick);
}
System::Void Form_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
if(e->KeyCode == Keys::Up){x=true;m1 = gcnew missile(this);m1->Box1->Left = Box2->Left + (Box2->Width / 2) - 10;}
if(e->KeyCode == Keys::Left){Box2->Left -= 4;}
if(e->KeyCode == Keys::Right){Box2->Left += 4;}
if(e->KeyCode == Keys::Down) {o1 = gcnew object(this); }
}
System::Void timer3_Tick(System::Object^ sender, System::EventArgs^ e)
{
if(x==true)
{
if(m1->Box1->Top == o1->Box3->Bottom){m1->Box1->BackColor = Color::Green;}
}
}
bool isColliding(PictureBox^ box1, PictureBox^ box3)
{
Rectangle r1 = m1->Box1->Bounds;
Rectangle r2 = o1->Box3->Bounds;
return r1.IntersectsWith(r2);
}
};
[STAThread]
int main()
{
Application::Run(gcnew Form1());
}
I also am trying to figure out how to remove the instances from memory after a set amount of time as too many instances slows the program.
Thanks for the help.
|
|
|
|
|
 I think your real slowdown comes from having a timer in each individual missiles. They keep ticking even after they've left the screen. And you never stop the timer and unsubscribe the tick event in each missile. This keeps the timers and missiles all alive all the time.
I've tweaked your code some and removed those separate timers and just update all the missiles from the Form's timer. Also, I remove the missiles which have gone off-screen so those won't be updated after they're gone . This should allow for more missiles and better perf/memory usage.
There are clearly other improvements you could do such as having the logic to determine whether a missile is off-screen determined by the missile class.
I hope this helps you get going...
John
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Collections::Generic;
public ref class object{
public:
PictureBox^ Box3;
object( Form ^ form )
{
Box3 = gcnew PictureBox();
Box3->Left = 150;
Box3->Top = 50;
Box3->Width = 100;
Box3->Height = 100;
Box3->BackColor = System::Drawing::Color::Red;
form->Controls->Add(Box3);
}
};
public ref class missile{
public:
PictureBox^ Box1;
missile( Form ^ form )
{
Box1 = gcnew PictureBox();
Box1->Left = 150;
Box1->Top = 240;
Box1->Width = 10;
Box1->Height = 10;
Box1->BackColor = System::Drawing::Color::Blue;
form->Controls->Add(Box1);
}
void update()
{
Box1->Top--;
}
};
public ref class Form1 : public System::Windows::Forms::Form
{
public:
PictureBox^ Box2;
object^ o1;
Timer^ Timer3;
bool x;
List<missile^>^ Missiles;
Form1()
{
Missiles = gcnew List<missile^>();
x=false;
Timer3 = gcnew Timer();
Timer3->Interval = 1;
Timer3->Start();
Box2 = gcnew PictureBox();
Box2->BackColor = Color::Blue;
Box2->Top = 240;
Box2->Left = (this->Width / 2) - 40;
Box2->Width = 40;
Box2->Height = 10;
this->Controls->Add(Box2);
this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &Form1::Form_KeyDown);
Timer3->Tick += gcnew System::EventHandler(this, &Form1::timer3_Tick);
}
System::Void Form_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
if(e->KeyCode == Keys::Up)
{
x=true;
missile^ m = gcnew missile(this);
m->Box1->Left = Box2->Left + (Box2->Width / 2) - 10;
Missiles->Add(m);
}
if(e->KeyCode == Keys::Left) {Box2->Left -= 4; }
if(e->KeyCode == Keys::Right){Box2->Left += 4; }
if(e->KeyCode == Keys::Down) {o1 = gcnew object(this); }
}
bool IsMissileOffScreen(missile^ m)
{
return m->Box1->Bottom < 0;
};
System::Void timer3_Tick(System::Object^ sender, System::EventArgs^ e)
{
for each (missile^ m in Missiles)
{
m->update();
if(x==true && o1 != nullptr)
{
if (m->Box1->Top == o1->Box3->Bottom)
{
m->Box1->BackColor = Color::Green;
}
}
}
Missiles->RemoveAll(gcnew Predicate<missile^>(this, &Form1::IsMissileOffScreen));
}
bool isColliding(PictureBox^ box1, PictureBox^ box3)
{
Rectangle r2 = o1->Box3->Bounds;
for each (missile^ m in Missiles)
{
Rectangle r1 = m->Box1->Bounds;
if (r1.IntersectsWith(r2))
return true;
}
return false;
}
};
|
|
|
|
|
Also, if you want to detect a collision, change the logic in the timer tick:
System::Void timer3_Tick(System::Object^ sender, System::EventArgs^ e)
{
for each (missile^ m in Missiles)
{
m->update();
if(x==true && o1 != nullptr)
{
if (o1->Box3->Bounds.IntersectsWith(m->Box1->Bounds))
{
m->Box1->BackColor = Color::Green;
}
}
}
Missiles->RemoveAll(gcnew Predicate<missile^>(this, &Form1::IsMissileOffScreen));
}
Other advice: It would be courteous to let us know that you've posted about this in the C++ forum as well to prevent duplication of efforts.
John
|
|
|
|