#68121 - ProblemBaby - Sun Jan 22, 2006 6:52 pm
Hello
Iam planning to make a small script language I can use for the DS. Because everything have to be put in the bin anyway, I think its best to have pure code instead of an action based script. So my first question is
it possible to compile ASM code like:
Code: |
LDR r0, [r7]
ADD r0, r0, #1
STR r0, [r7]
POP { r0-r7, pc }
|
and as output just get the opcodes, no ELF, no linking, just pure code.
Further I thinked it would be a waste of time to make my own language if it would be possible to compile C-Code in the same way.
Thanks
#68128 - sajiimori - Sun Jan 22, 2006 7:22 pm
Quote: |
Because everything have to be put in the bin anyway, I think its best to have pure code instead of an action based script. |
By "pure code" and "action based script," I assume you mean ARM opcodes and interpreted bytecodes. If so, there are two main benefits of interpreted bytecodes: they can be specialized for a particular purpose which makes them more compact, and they can be made platform-independent. Whether these benefits are compelling depends on the project.
Quote: |
So my first question is it possible to compile ASM code ... and as output just get the opcodes, no ELF, no linking, just pure code. |
But "pure code" is exactly what you get when you create a .bin the usual way. The fact that the intermediate stages involve linkers and ELF files doesn't make any difference -- you start with source code and end with a raw binary.
#68146 - ProblemBaby - Sun Jan 22, 2006 8:47 pm
I forgot several things when I wrote the makefile! Now it works for ASM-code how about c-code, when I try to compile I get: crt0.o no such file or directory, why?
#68176 - sajiimori - Sun Jan 22, 2006 11:37 pm
At this point, I don't really know what you're trying to do or how you're trying to do it.
#68179 - keldon - Sun Jan 22, 2006 11:49 pm
A scripting language is very easy to implement. Much easier than I am guessing you imagine it is.
#68314 - Miked0801 - Mon Jan 23, 2006 7:49 pm
Scripting system 101 - can also double as a Finite State Machine in a pinch. Untested, but you get the general idea of how it works. Easily extensible.
Code: |
typedef void (*SCRIPT_FUNCTIONS) (u32 param);
// Add commands here
typedef enum
{
COMMAND_ADD_ITEM
COMMAND_FLASH_SPRITE
COMMAND_MAX
} SCRIPT_COMMAND;
// Prototype script functions here
static void ScriptAddItem(u32 param);
static void ScriptFlashSprite(u32 param);
// Add functions to table here
static const SCRIPT_FUNCTIONS ScriptCommandTab[COMMAND_MAX] =
{
ScriptAddItem,
ScriptFlashSprite,
};
// Main script run routine
void scriptRun(SCRIPT_COMMAND command, u32 param)
{
ASSERT(command < COMMAND_MAX);
ScriptCommandTab[command](param);
}
// Helper functions start here
static void ScriptAddItem(u32 param)
{
// Do add item code
}
static void ScriptFlashSprite(u32 param)
{
// Do flash sprite code
}
|
#68458 - ProblemBaby - Tue Jan 24, 2006 7:53 pm
Yeah, but I need a 'not just function calling'-script. It turns out to a total mess when you have about 100 source files, I want something external that takes care of characters, dialogues etc.
I think the already existing game scripts runs to slow. The ultimate solution would be if I could use C as the scripting langauge and compile the file separatly and then send the file as a parameter to my runScript function and then have a buffer where I put the variables/functions, that I can load to the script. Would it be possible to do?
Its so hard to explain in english!
hope the script example makes it a bit clearer.
Code: |
// my Script
extern s32 xPlayer = LoadVar(0);
extern s32 yPlayer = LoadVar(1);
extern void SetCameraPos(s32 x, s32 y) = LoadFunc(2);
void Script()
{
if (xPlayer < 20)
xPlayer++;
SetCameraPos(xPlayer, 8);
// etc..
}
|
#68462 - sajiimori - Tue Jan 24, 2006 8:16 pm
What's wrong with just writing the code and linking it in normally? Are you concerned about code size?
#68464 - ProblemBaby - Tue Jan 24, 2006 8:40 pm
1. 1000 source files in the project (a lot of prototypes etc = mess)
2. Ive to recompile all files if I do something in a header it uses.
3. Its much more clean to refer to scripts as "files" instead of function calls.
Of course its most to keep it clean! I can't imagine that a large rpg have their scripts as normally linked source files.
I succeeded to write this kind of code in ASM, just write some instructions and got the opcode output. but not in C, how can I compile something like this:
Code: |
void IDontCareAlwaysInterpretThisAsTheStart(SCRIPT_STRUCT *scrStruct)
{
scrStruct->x++;
}
|
and just get the opcode output like:
Code: |
LDR r1, [r0]
ADD r1, r1, #1
STR r1, [r0]
POP { pc }
|
#68465 - sajiimori - Tue Jan 24, 2006 9:32 pm
Quote: |
1. 1000 source files in the project (a lot of prototypes etc = mess) |
If I understand your intent correctly, it sounds like you'll have the same number of source files either way.
Quote: |
2. Ive to recompile all files if I do something in a header it uses. |
Don't include the headers globally. Include them in a single .c file that will serve as the proxy interface to all scripts. Then if you change a header, only the proxy gets recompiled.
Quote: |
3. Its much more clean to refer to scripts as "files" instead of function calls. |
Not in any objective way.
Quote: |
Of course its most to keep it clean! I can't imagine that a large rpg have their scripts as normally linked source files. |
There's no point in being abnormal for its own sake.
#68472 - Miked0801 - Tue Jan 24, 2006 10:11 pm
So take my example 1 step further and have an external program store "byte codes" for the scripts - then pass those byte codes into the function table pointer. That is basically how the last few RPGs I worked on handled scripting.
#68497 - ProblemBaby - Wed Jan 25, 2006 2:36 am
Quote: |
If I understand your intent correctly, it sounds like you'll have the same number of source files either way
|
No.
GreenBlob.c
BlueBlob.c
CastleOfDawn_BrownSpearKnight.c
Forest_BrownSpearKnight.c (this one doesnt act like the one in the castle)
etc..
Putting all this kind of characters update code in one file is not a good idea and the names will be so complex.
Scripting such things makes it so much easier to work with.
Quote: |
So take my example 1 step further and have an external program store "byte codes" for the scripts - then pass those byte codes into the function table pointer. That is basically how the last few RPGs I worked on handled scripting.
|
I want something more out of my script or do you have actions like 'if'
a such action have to make a lot of if-tests to see what kind of condition, variable/constant etc. thats a real waste.
isnt it possible to compile C-code like ASM-code and just get the raw output. or do Ive to write my own C->ASM converter.
Do you still dont see my aim?
#68504 - ProblemBaby - Wed Jan 25, 2006 4:32 am
Ive find out to do what I want, just passing nostartupfiles to gcc and I got what I wanted.
#68508 - sajiimori - Wed Jan 25, 2006 5:17 am
Quote: |
Putting all this kind of characters update code in one file is not a good idea and the names will be so complex. |
Nobody suggested that you put them in one file.
#68523 - sgeos - Wed Jan 25, 2006 9:19 am
Why is this bad?
Code: |
typedef void (*SCRIPT_FUNCTION) (u32 pParamCount, u32 * pParamList); |
-Brendan
#68533 - ProblemBaby - Wed Jan 25, 2006 12:17 pm
sajimori: no but instead ive will have a hell lot of sourcefiles.
Quote: |
Why is this bad?
Code:
typedef void (*SCRIPT_FUNCTION) (u32 pParamCount, u32 * pParamList);
|
It isnt bad, but I want to do more advanced things than just have a flow of called functions. Of course its possible to put Simple functions like: if, add, etc but that turns out to C-like language that runs about 10 times slower.
#68534 - sgeos - Wed Jan 25, 2006 12:20 pm
ProblemBaby wrote: |
sajimori: no but instead ive will have a hell lot of sourcefiles. |
If you make anything big you'll have a lot of source files.
ProblemBaby wrote: |
I want to do more advanced things than just have a flow of called functions. |
What do you want to do?
ProblemBaby wrote: |
that turns out to C-like language that runs about 10 times slower. |
You can translate it to C if you want to. Then it will run just as fast as C.
-Brendan
#68542 - ProblemBaby - Wed Jan 25, 2006 4:32 pm
Quote: |
You can translate it to C if you want to. Then it will run just as fast as C.
|
Yeah, Ive found out how I can write it in C directly and run it without having to link it to the project, thats really nice. I dont have to mix the engine code with other stuff like dialogues, enemy controlling, forced player actions etc.
#68568 - Miked0801 - Wed Jan 25, 2006 7:29 pm
Ok, I'm fairly confused now. You don't want a byte-code based scripting system because it doesn't have the power of compiled code and doesn't run as fast. I guess I am missing the point completely in why you want a scripting system.
Scripting systems allow non-programmer type people a chance to create a large portion of a game with external tools and very little engine exposure. They can also be treated like a macro system to allow your engine controller (we call them actors), to do simple tasks very quickly from the code side. Interpretation/run speed should not be a problem here - this code is run at a very high level and not very often.
Can a byte lookup language have conditonals and loops? Yes! We have if/else/then, loops via jumps, variable assignments, and just about anything else you could want. It codes very much like BASIC truth be told. A scripting language can be whatever you want it to be - from straight C calls to a BASIC interpretor to even LISP if you wish. I guess I'm confused as to what you mean be a scripting language. I'll go re-read your original post and ponder...
#68571 - sajiimori - Wed Jan 25, 2006 7:34 pm
Quote: |
no but instead ive will have a hell lot of sourcefiles. |
I'm confused, too. First you said you didn't want to put everything in one file, now you're saying you don't want to have a lot of separate files. What do you want?
#68585 - ProblemBaby - Wed Jan 25, 2006 10:05 pm
Iam confused too...
I will try to be as clear as I can.
Sajimori/Miked: Iam just trying to answer your questions=) Yes, first I said I dont want a hugh file linked to the project with each script as a function neither put each script in a single file and link them to the project. I want something external, something that isnt mixed with my game engine.
Miked: For me it doesn't care if a non-programmer understands or not Cause I want it quite complex to make it fast.
Maybe iam wrong but ByteCode-script for me means a table of functions and you refer to them as IDn and a parameter list. Thats fine if you dont want complex scripts (I think!). Cause... imagine an if-function
you need several if-tests to see what kind of condition it is.
=, <, >, >=, <=, !=, &, | etc. Further is it a constant you want to check, what kind of variable, signed, unsigned, bits?
Its a lot of code for just a simple if-test, maybe iven't really understood it.
Further I dont want to make my own language that translates the code to C, cause it would be much like C anyway.
I just want to be able to compile files outside the project, put them ROM.
When I want to Init a Script, I just copy the script to MainRam and jumps to the position, fast, easy and the project is still manageble.
Iam now able to do what I want so I dont need any help so thats no problem, but it would be nice if someone could understand why I want to this.[/code]
#68601 - sajiimori - Thu Jan 26, 2006 12:20 am
I think you're making an artificial and unnecessary mental distinction between things that are included in the ROM using the linker, and things that are included in the ROM using some other tool. It's not that there is no difference, but using the linker doesn't cause the problems you seem to be concerned about.
The linker is just another tool, and not everything it touches has to be considered part of the "engine." The distinction between "engine code" and "data" is conceptual, and not based on which tool was used to include it in the ROM.
#68609 - ProblemBaby - Thu Jan 26, 2006 1:06 am
But what do you think I should do?
A good system for handling all of my npcs, dialogues everything a usual script takes care of? wouldn't an usual game script language, like lua or python be slow in such limited hardware?
if you think thats better, why?
#68612 - poslundc - Thu Jan 26, 2006 1:37 am
No one suggested LUA or Python. They are not the same thing as a straightforward bytecode-to-jumptable interpreter (which is what most people have been suggesting you do).
You don't need anything as heavyweight as LUA (although there are a lot of good ideas you could take from it) and you don't need anything as lightweight as scripts compiled to native ARM code.
Give a function table a try. I'll wager a steak dinner your scripting barely even registers as a blip on your finished game when you profile it.
Dan.
#68614 - ProblemBaby - Thu Jan 26, 2006 1:53 am
Quote: |
No one suggested LUA or Python. They are not the same thing as a straightforward bytecode-to-jumptable interpreter (which is what most people have been suggesting you do).
|
Yeah I know. But Ive also said that I need something more complex. For example a function like MoveChar isnt enough for me, I would need about 100 kinds of different MoveChar functions, maybe I can get it two 20 if I define everything like, walkability on different surfaces, weight, etc. etc, again it will end up with 2000 lines, of different actions.
and iam afraid of things like: oh Ive to change the flyingbanana movement a bit, oh now, the dragon were affected, aargh.
I want to know how its done in games like Castlevania dawn of sorrow and games like that.
Quote: |
You don't need anything as heavyweight as LUA (although there are a lot of good ideas you could take from it) and you don't need anything as lightweight as scripts compiled to native ARM code.
|
No I know Ive played with c-code, and it doesnt feel real good.
#68617 - sajiimori - Thu Jan 26, 2006 2:24 am
Quote: |
But what do you think I should do? |
All things being equal, the simplest thing is to write your scripts in C and link them in normally. To avoid excessive dependencies, access all the scripts through a single proxy module. To avoid file management headaches, keep your script files in a separate directory. To avoid build headaches, make your build process automatically compile and link in every file in the script folder.
For some projects, other approaches are better. You might need a different approach if:
- ...your scripters don't know C, and have little programming experience. A simpler language may be necessary.
- ...C is too low-level to write your scripts in an elegant manner. High-level languages like Lua are nice, but C++ might be enough.
- ...the code uses too much memory. Scripting languages can solve the problem, but you could also dynamically load native code using overlays or relocatable modules. It's mostly safe to ignore this issue until it comes up because you can always convert existing code to be dynamically loaded. It may never be necessary.
- ...you want to write and test code at run-time. This is a non-issue for DS-only games, but if you port your engine to the PC, you could have an interpreted scripting language and edit code while the game is running.
#68619 - poslundc - Thu Jan 26, 2006 2:29 am
ProblemBaby wrote: |
Yeah I know. But Ive also said that I need something more complex. For example a function like MoveChar isnt enough for me, I would need about 100 kinds of different MoveChar functions, maybe I can get it two 20 if I define everything like, walkability on different surfaces, weight, etc. etc, again it will end up with 2000 lines, of different actions.
and iam afraid of things like: oh Ive to change the flyingbanana movement a bit, oh now, the dragon were affected, aargh. |
This is why you supply parameters to your commands.
Quote: |
I want to know how its done in games like Castlevania dawn of sorrow and games like that. |
On what evidence are you basing the assumption that Castlevania does things any differently from what people in this forum have been describing?
Why would a function table not good enough for Castlevania?
Quote: |
No I know Ive played with c-code, and it doesnt feel real good. |
Can you come up with a more substantive reason than it doesn't feel real good?
Dan.
#68628 - ProblemBaby - Thu Jan 26, 2006 2:59 am
Sajimori: yeah, thats probably the best way! But I cant still decide if I should have a function table or code.
I really thought my idea would be nice, but it ended up with hugh problems when I wanted to call functions from the engine.
First the parameters and second if I change the functiontable sent to the external code i had to recompile every script anyway!
Quote: |
This is why you supply parameters to your commands.
|
What I wanted to say was that I would need more complex functions then just a function called Char_Move, Char_Attack etc. cause its so different depening on what it is and I dont want to send a WalkStyle param with 20 different types. I want to have like separate functions/scripts for each kind of character.
like this, its too haevy. its almost unnecessary to have a script.
Code: |
// script for a kind of enemy
// not
0x12 0xC // Char_Move(12);
0x13 0x16 //if (Char_CloseToPlayer())
0x15 0xC //Char_Attack(12);
|
Quote: |
hope it was understandable.
On what evidence are you basing the assumption that Castlevania does things any differently from what people in this forum have been describing?
Why would a function table not good enough for Castlevania?
|
I dont!
I was more interested in how you think they had designed it. Cause its so much different kind of AI, movement styles, attacks etc.
Quote: |
Can you come up with a more substantive reason than it doesn't feel real good?
|
I were really unclear, have you read the earlier posts? anyway that idea wasn't as good as I thought that was what I meant.
#68632 - poslundc - Thu Jan 26, 2006 3:24 am
I think perhaps you are confusing AI with scripting. They are similar enough in purpose that it can be difficult to tell where one starts and the other ends.
Defining different modes and patterns to govern enemy behaviour and logic is tough to do within a script. That's the kind of thing you want to program a specific module for, and have the different states the enemy can be in a rigidly defined set, as well as a system for determining under what circumstances they will go from one state to another.
A script is something you might use to manually assign one of those states to an enemy, or contain instructions for the actual physical steps an enemy has to execute, once a course of action has been determined.
Dan.
Last edited by poslundc on Thu Jan 26, 2006 3:25 am; edited 1 time in total
#68633 - DekuTree64 - Thu Jan 26, 2006 3:25 am
ProblemBaby, I was in the exact same situation as you back when I was working on my old RPG. I didn't know exactly what a scripting system would need to do, or what kind of system to make.
I ended up doing it in C code. Just a function pointer table for each map, with a function for each "event". They could be triggered by stepping on map tiles, or pressing A while facing a tile or sprite.
Basically I wrote a simple set of functions similar to a scripting language. For example, MapEventMoveSprite(u32 spriteID, const char *moveScript). The move script would just be a string, like "ldru" would make him walk in a circle, and the sprite ID was a #define generated by my map editor based on the name you gave the sprite.
Anyway, it worked, and didn't impose any limits. It saved a lot of time being able to code things in an event where I needed it, and then generalize to engine code if I ever needed the same thing again. And if the only people doing the scripting are programmers, there's really not much disadvantage aside from probably taking more ROM space than a bytecode system.
EDIT: I started writing this post several hours ago, but went back to working on other things. There's been lots of good discussion since then, but I guess it's still applicable :)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#68635 - ProblemBaby - Thu Jan 26, 2006 3:46 am
Thanks a lot for the replies!
Quote: |
Defining different modes and patterns to govern enemy behaviour and logic is tough to do within a script. That's the kind of thing you want to program a specific module for, and have the different states the enemy can be in a rigidly defined set, as well as a system for determining under what circumstances they will go from one state to another.
A script is something you might use to manually assign one of those states to an enemy, or contain instructions for the actual physical steps an enemy has to execute, once a course of action has been determined.
|
This was really intersting cause that was the biggest thing ive thought of!
That was the main thing why I wanted it in C, cause it would be so complicated for different kind of chars, but AI is very "level" independent (its enough with a few variables that tells how it acts) and it isnt that much kind of actions so ive to do it unique to every character.
DekuTree64: nice to hear some thoughts from one that have been trough the same situation.
I think I'll write it entirly in C too. But first Ive to find out what I want to be able to support! Ivent even thinked of map triggers yet=(
Last edited by ProblemBaby on Thu Jan 26, 2006 1:37 pm; edited 1 time in total
#68639 - sajiimori - Thu Jan 26, 2006 5:24 am
Personally, I've often encountered mental blocks when trying to think of every possible thing that I could want, and the best approach to accomplish all of those things, before ever writing a line of code.
Sometimes it's just too hard to predict everything that will ever be needed, especially if you're in unfamiliar territory. I'd say just start writing things in the simplest way you can think of, and change it if a better way becomes clear.
Don't worry about running into a dead end and having to rewrite code. Some of the worst code I've seen was a result of an unwillingness to throw out old code and start again. The Quake engine was completely rewritten a dozen times before Quake 1 ever came out, because it was such an experimental project.
#68721 - sgeos - Thu Jan 26, 2006 3:07 pm
[Re: AI]
ProblemBaby wrote: |
This was really intersting cause that was the biggest thing ive thought of!
That was the main thing why I wanted it in C, cause it would be so complicated for different kind of chars, but AI is very "level" independent (its enough with a few variables that tells how it acts) and it isnt that much kind of actions so ive to do it unique to every character. |
If you are interested in AI, why don't you buy a book on the subject and come back here when you have specific questions?
sajiimori wrote: |
when trying to think of every possible thing that I could want |
Been there, done that. I think it's better to just make something and see how it turns out. (Evidently I agree with you...)
-Brendan
#68726 - ProblemBaby - Thu Jan 26, 2006 3:46 pm
Quote: |
If you are interested in AI, why don't you buy a book on the subject and come back here when you have specific questions?
|
It was just the different approach that interested me. but you are right a book would be nice!
Quote: |
sajiimori wrote:
when trying to think of every possible thing that I could want
Been there, done that. I think it's better to just make something and see how it turns out. (Evidently I agree with you...)
|
I agree too
#68787 - sajiimori - Thu Jan 26, 2006 8:00 pm
The only useful piece of information I've ever gotten from an AI book was the A* algorithm, widely available on the internet. Everything else I've done for AI feels like "normal" code to me. I just try to say things in the simplest way, and if that's not immediately possible, I make a utility that makes it possible.
For example, if I want my character to walk right until it hits a wall and then jump, the code should ideally look something like this:
Code: |
while(!hitWall())
walkRight();
jump();
|
Unfortunately, this blocks the rest of the game from running, so time would be frozen while the character walks to the wall.
The usual solution is a finite state machine. My preferred solution is asymmetric coroutines, which make the code look like this:
Code: |
while(!hitWall())
{
walkRight();
yield(); // Allow 1 game tick to pass.
}
jump();
|
#68986 - Miked0801 - Fri Jan 27, 2006 8:14 pm
Or for FSM driven engines:
Code: |
void ai_func(void)
{
switch(ai.state)
{
case WALK_RIGHT:
if(hitWall())
{
ai.state = HIT_WALL;
jump();
}
break;
case HIT_WALL:
// Whatever
break;
}
}
|
Nothing slow or hard to understand there.
#68995 - sajiimori - Fri Jan 27, 2006 8:56 pm
Well, the code is twice as long... ;)
Besides that, the code ends up being suspiciously like BASIC. Assigning state variables is like goto, but with coroutines you get structured control flow.
I still use hand-written state machines when the current state needs to be accessible and assignable from outside the module.
#69420 - Miked0801 - Mon Jan 30, 2006 6:21 pm
And what's wrong with BASIC? Besides spaghetti, gotos, hard to debug, ... :)
#69444 - tepples - Mon Jan 30, 2006 8:31 pm
Miked0801 wrote: |
And what's wrong with BASIC? Besides spaghetti, gotos, hard to debug, ... :) |
Nothing. Modern BASIC dialects going all the way back to QBasic have done away with spaghetti code, replacing line numbers with typical structured programming constructs (if() then ... else ... end if) (do while() ... loop). In fact, they look a lot like Pascal, C, or any other Algol clone, and VB.NET is just as powerful as C# or Java.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#69469 - sajiimori - Mon Jan 30, 2006 11:32 pm
Right -- Mike and I are thinking of older dialects.
#69545 - sgeos - Tue Jan 31, 2006 12:55 pm
sajiimori wrote: |
Right -- Mike and I are thinking of older dialects. |
C64 basic. =) peek poke
-Brendan
#69588 - poslundc - Tue Jan 31, 2006 5:47 pm
You young'uns may giggle, but peek and poke aren't all that different from C pointers, and a lot of what you did on the C64 (or in my case the Apple II) to tweak hardware features with those instructions is exactly what you're doing on the GBA anyway.
They're all procedural languages, all capable of the same thing. C offers structural features (now considered fundamental) that simplified and automated constructs you could still create in classic line-number BASIC (if you were disciplined enough) in the same way C++ offers structural features that simplify and automate constructs you can still create in C (if you are disciplined enough). Unless you're talking about something fundamentally different (compiled versus assembled, procedural versus functional, etc.) you won't be saying anything meaningful by looking at the whitepapers alone.
What's relevant is that a language lends itself to a certain style of programming (and here's where I might lose some people), in the context of when and why it was invented in the first place.
People always associate BASIC with spaghetti-programming, but remember that even line-number BASIC had the GOSUB instruction, and you could write a quicksort engine in C without using a single function-call or native loop structure if you wanted.
Dan.
#69610 - tepples - Tue Jan 31, 2006 8:09 pm
poslundc wrote: |
but remember that even line-number BASIC had the GOSUB instruction |
Which did not provide for local variables, unlike the later structured BASIC dialects.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#69802 - Miked0801 - Thu Feb 02, 2006 12:29 am
I always hated GOSUB when coding C64 basic. I was more comfortable with gotos as I knew exactly where the code was returning/jumping.
sys 64320
Poke 53281,0
Poke 53280,0
poke 646,1
or for real fun
poke 53265, 4 (or was it 16)
The truely sad part is I didn't have to look these up.