Thank you hornet for the useful input.
For clarity, what exactly are you talking about when you mention scripting? I'm a bit confused whether you intend to do all this in c++ or employ a full scripting engine with external scripts (or maybe a bit of both)?. Usualy the term scripting would mean the latter but the way you talk about it makes me think the former.
For the moment, I want to hardcode everything into C++. Later when I'm familiar with it, I want to move onto scripting and have the object behaviors/definitions done externally. The problem, as implied, is actually doing things over time. I'm not sure how to tackle that without putting if(framenumber==whatever) statements everywhere, which is why I'm so obsessed about the idea of yield that Danmakufu so successfully does. Being able to delay object creations and function executions without having to redo everything from scratch. Getting these objects to inherit behaviors is also very important to me for ease of access and manipulation of what I want and when these objects to do [stuff].
Here's an example of Danmakufu's stage script. The stage script is a multipurpose document used to spawn enemy objects and bullets. The enemy objects themselves run seperate scripts written especially for them that defines their behavior. And more than one object can run the same script. So I'm able to make several enemies of the same type in the stage.
script_stage_main{
@Initialize{
intro();
while(stage_start==0){yield;} //delay everything below until the player selects "start"
CreateEnemyFromFile("Behavior1.txt",xpos,ypos,valuetopass,sprite2);
loop(400){yield;} ///delay everything below by 400 frames.
CreateEnemyFromFile("Behavior 4.txt",xpos,ypox,valuetopass,sprite4);
CreateEnemyFromFile("Behavior 4.txt",xpos,ypox,valuetopass,sprite4); ///spawned at the same fame as the above
loop(100){yield;}///suspend the next functions by 100 frames.
CreateEnemyFromFile("Behavior 1.txt",xpos,ypos,valuetopass,sprite1);
///it doesn't matter if the last object inherits the same document as the first.
///it runs from the beginning of the script, the two objects are practically separate
}
@MainLoop{
DoThisStuffEveryFrame(); ///self explanatory
}
@Finalize{
if(lives==0){ask_continues();}
}
}
The definitions of the objects' behaviors is similar.
[Behavior 4.txt document]
script_enemy_main{
let angle=SomeMathFunction();
@Initilaize{
loop(50){yield;} ///wait a few frames before doing the executions below
stuff();
morestuff(); ///executed the same frame as the above despite the above function having yields within it
}
@MainLoop{
dothiseveryframe();
}
@Finalize{//runs when the object's "life" reaches zero or when it leaves the screen
explode();
}
function stuff(){
while(player=alive){shootbulletatplayer(); yield} //shoot a bullet at the player every frame
}
function morestuff(){
///motion functions here.
///function stuff()'s yielding does not affect the execution procedure of this thread
}
function explode(){bulletseverywhere();}
}
But how can I get object index 1 to inherit the behaviors stored in the given document?
Here's what I have. The struct for my objects are similar to that of the bullets. They are made in an array, and can be reused like bullet can. The reason is, as you may have guessed, because I'll be using numerous objects at any given time.
struct LIVEOBJECT{
bool alive;
float xpos;
float ypos;
float direction;
float speed;
int idnum;
OBJDATA objdata; //stuff like sprites/texturs and UV coordinates stored here
}
And just like the bullets struct, this struct has its own vertex buffer, DrawPrimitive function, all that small stuff.
Now, here's the function called in my infinite loop that renders a single frame.
void render_one_frame(){
d3ddev->BeginScene();
d3ddev->Clear(NULL,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,255),1,0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
events(); ///I want to avoid putting things here because they'll be done every frame
///if I do so. I need some sort of yield function that delays function executions I call
///throughout the game-time so I don't have to make an if-then statement
///every time I don't want my object's functions to be done every frame.
///this is the obstical that's preventing me from advancing.
render_3D_background(); ///this is done.
render_cameracontrols(); ///this is done.
render_livingobjects(); ///similar to render_bullets. Objects inherit behaviors written in a document.
render_staticobjects(); ///special effects. Similar to render_bullets and render_livingobjects
render_bullets(); ///bullets drawn here.
render_text(); ///point system. This is done.
d3ddev->EndScene();
d3ddev->Present(NULL,NULL,NULL,NULL);
framecount++; ///framecount goes up by 1 every frame.
}
If I wanted to oh, say.. make a bullet spawn every 20 frames, I don't want to have to do this in my events() function.
{static framen=0;
if(framen==20){CreateShot(X,Y,whatever); framen=0;}
framen++;
}
Of course, I'd LOVE to be able to do this...
///events function is called once, outside my infinite loop.
Sleep(1000); //delay a second.
for(int i=0; i<20; i++){
for(int i=0; i<60; i++){
CreateShot()///shoot 60 bullets in a circle
}
Sleep(MilisecondsPerFrame); ///wait x-frames, so it shoots 60 bullets, 20 times over, x-frames waiting time every round.
}
////nothing else happens beyond this point.
////since events() is called once, and outside my infinite loop, this would
////be done in chronological order
///if it was this easy, making a yield function would be as easy as defining it
///int nextframe=framecount+1;
///while(nextframe!=framecount){sleep(1);} ///not correct, but get the idea..
Unfortunately, the Sleep function delays ALL processes, not just the processes executed by the thread it's called in like yield does.
It's ridiculous. I want to have a timeline that revolves around yield.
I know it's possible to use the infinite game loop to do the things I want when I want by using a timer or framecounter, but it gets obnoxiously tedious having if(framecountnumber==whatever) statements everywhere to do it. Not to mention the "stage" code that handles everything from camera motion to enemy spawns will be incredibly long to begin with, and having it in the middle of an infinite loop with if-then statements everywhere that tells what happens when is so obsurd it's laughable.