Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Calin Leafshade

#61
Ok so a while ago someone (Icey Games i thnk) expressed an interest in using spritefonts because he has totally got the rest of his game down and wanted to add some sparkle.

Now SSH wrote a spritefont module but it was awkward to use since it didnt integrate with the normal ags text functions. This plugin solves that problem.

So you can set a spritefont to override a normal font and just use .Say() or Display() calls and the plugin will draw.

This means you can bypass all the issues with font outlining and stuff just by providing your own, multi coloured, anti aliased, fonts.

Functions

Code: ags

//sets a fixed width font
void SetSpriteFont(int fontNum, int sprite, int rows, int columns, int charWidth, int charHeight, int charMin, int charMax, bool use32bit)


where:

fontNum is the font number you wish to replace.
sprite is the sprite number that contains the sprite font
rows is the number of rows in the font
columns is the number of columns
charWidth is the width of a single character (must all be the same)
charHeight ditto height.
charMin is the lowest ASCII number that the font contains
charMax ditto highest.
use32bit is currently unused and can be either true or false.

the spritefont must be formatted sequentially like this one:



the function for this one would be:

Code: ags

SetSpriteFont(0, 1,  3, 20, 16, 16, 32, 91, true);


Code: ags

void SetVariableSpriteFont(int fontNum, int sprite);


This overrides font 'fontNum' with sprite 'sprite'

Code: ags

void SetSpacing(int fontNum, int spacing)


This allows you to adjust the spacing of a variable width font if its too spread out with drop shadows and stuff

Code: ags

void SetGlyph(int fontNum, int charNum, int x, int y, int width, int height)


This sets a glyph (character) size and location in the spritefont's texture.

I have included a utility which will generate the code for you.

Usage of variable width fonts

- In the archive is a program called SpriteFont.exe. This program will generate variable width sprite fonts for you with shadows and outlines and all kinds of shit.
- The program generates 2 files. The PNG which is the actual font and a file called metrics.xml.
- In the archive there is also AGSSpriteFontGen.exe. This program will take the metrics.xml and convert it to AGSScript that you can copy into your game.

download

The archive contains a demo and all the files needed.

The helper programs need .Net4.0 to run but the plugin itself has no dependencies.

https://dl.dropboxusercontent.com/u/20918686/ags/ags_sprtitefont.zip

What does it look like? Is it better than AGS's normal font renderering?

Yes it is. It looks like this:

#62
I'm bored at work.

Argue with me about something. If you are a creationist, climate change denier, homeopath, astrologer, flat-earther, geocentrist or conspiracy-theorist you are welcome to argue your case, after which I shall present a rebuttal, after which i might have a drink of apple juice.
#63
General Discussion / New version of aseprite!
Wed 10/08/2011 17:05:32
This is not really a new version but some new and useful functions have been added to the git repository.

I have uploaded a compiled version here: http://www.thethoughtradar.com/aseprite-latest.zip

New features of note include:

- An accurate palette quantize that extracts palette from an image for easy palette editing.
- Import from and export to a sprite sheet
- Mini editor so you can see your sprite at 1x zoom whilst working on it at a higher zoom.
- Bug fixes
#64
You may listen to it here:

http://www.thethoughtradar.com/blog/?p=242

Your comments on the production and performance would be appreciated

*END COMMUNICATION*
#65
Hello forumites

Does anyone drink tropicana 'pure premium' juice (100% squeezed)?

I'm collecting the codes underneath the cartons so if anyone drinks it and doesnt want the codes GIMME!

the codes look something like 166KA02041XDNW7
#66
General Discussion / USA 2012: The Candidates!
Wed 20/07/2011 09:37:02
Good morning denizens of the internet.

I have been following the evolution(lol) of the republican candidates in the US and I would like some American perspective.

Michelle Bachmann appears to be something of a favourite for the republican candidate alongside Mitt Romney. I am of the opinion that *both* of these people are batshit crazy/unqualified. What do you think?

While I think it would be fun (in a trainwreck kinda way) if Ron Paul won I can't really see that happening and even if he did the senate would never endorse any of his ideas. (Amusingly I actually think that Paul is *right* about the unconstitutionality of things like social security and FEMA but thats another story)

The rest of the candidates are no-hopers and thus I don't care about them.

Discuss.
#67
Critics' Lounge / Animation Critique
Mon 27/06/2011 15:41:02
So I attempted another walk cycle but i'm not entirely happy with it. Some comments would be welcome from some animation virtuosos.

#68
Some AGSers and I were discussing the possibility of a Trivial-Pursuit-like online game and we decided that it might be some fun.
However it was pointed out that you would need a shit-load of questions to make it even a slight possibility.

SO! With that in mind i decided to try and crowd source the problem and made OpenTrivia.
Open trivia is a website which allows you to add trivia questions to a database and answer them. When you answer the questions you are given the chance to rate them and say whether or not you knew the answer. This allows the questions to be rated by quality and difficulty.

If you are logged in (which is entirely voluntary) the site links the question to your account and saves how many you have answered.

So, with that in mind, I humbly ask you to go and add/answer some damn questions!

The only requirement is that the questions be fairly well formed in terms of grammar and punctuation. If a question sucks or its too hard then it will be rated as such, which should take care of the problem.

So go and give it a try!

http://svn.thethoughtradar.com/trivia/

EDIT: fixed in Firefox
#69
General Discussion / Adult cartoons
Wed 15/06/2011 08:55:14
Hola forumistas!

Firstly i should point out that when i say 'adult cartoons' i mean 'cartoons intended for adults', not porn.

So I'm a big fan of MTV's Downtown (http://www.youtube.com/watch?v=V7L0kgS19PM) and i wondered if anyone could suggest any other cool adult cartoons to me.

Anime and western are both fine.

#70
come and play now

Nevermind, game over

#71
Ok so anyone following the tech forum might have worked out that i'm working on a turn based RPG for a giggle.

Heres My class diagram thus far:
(It's large so i wont embed it)

http://i.imgur.com/EzGxf.png

You'll notice that the 'Lumberjack' branch is a little on the thin side. I'm trying to make a kind of rugged woodsmen type of class tree but i'm at a loss as to what else i can add to it.

Any ideas?

(Oh and the other classes might look a little unbalanced in places but i'm hoping to balance it out a little with special abilities for the classes.)
#72
I have another, more difficult algorithm to implement and I dont quite understand it.

Ok so imagine this fellow here:



He is an archer stood high up. So he should be able to fire his arrows further than someone at ground level.

now look at this fellow:



He has a big block of terrain in front of him which should block his line of sight.

Now how do i calculate where this guy can aim and also *how far* his shot will go in any particular direction.

I found this article on LOS but i dont really understand it much:

http://www-cs-students.stanford.edu/~amitp/Articles/LineOfSight.html

Help would be appreciated. I'll give you credit on ma gamez! (but only if SquareEnix dont want to work with me)
#73
I made a tutorial on how to make custom structs in C++!

I would appreciate it if some C++ type person could go through it and maybe tell me if I messed up anywhere with my definitions and explanations.

GO!

What you will need:

- A c++ compiler and some basic knowledge on how to use it. I suggest using Visual C++ Express from Microsoft since it is nice and comprehensive but also free.
- The template here: http://www.thethoughtradar.com/AGS/strippedplugintemplate.zip
- No... that's pretty much it.

What *is* a managed object

Without getting too technical about memory usage, a managed object (struct) is basically something that you can declare a pointer to. Built-in examples include DynamicSprite, Character, DrawingSurface and so on.

Why would I want one?

One advantage is to allow your code to be neater and more object oriented. Consider the following example:

Code: ags

struct Particle{
	int posX;
	int posY;
	int posZ;
	int colorRed;
	int colorBlue;
	int colorGreen;
	int colorAlpha;
	int spriteNumber;
};


Do you see a problem here? Wouldn't it be nicer if we could do this instead:

Code: ags

struct Particle{
	Point3D *position;
	Color *color;
	int spriteNumber;
};


Then, when accessing the members of the struct it looks like this:

Code: ags

//'part' is an instance of the Particle struct
part.color.red = 10;
part.position.x = 32;


Another advantage is that it allows you to pass whole structs from functions like this:

Code: ags

Color *GetColorFromAGSColor(int agsColor){

Color *toReturn = Color.CreateColor(agsColor);
return *toReturn;

}


Ofcourse this function is pretty stupid, you get the idea..

Without the color struct you would need 3 different functions for the red, green and blue components (or a selector of some kind) which is inefficient and messy.

Advantage number 3 is that it allows you to nest structs within one another like the Particle example above.

Ok Fine, I am still reading, show me how

Make a project!

First you'll need to get the plugin API header and example file that is linked above. This is a custom version of the demo given on the AGS site which removes all the superfluous stuff in there for demo purposes. Make a new  empty project in VC++ as a Win32 DLL and name it something beginning with the letters AGS. AGS won't load your plugin unless it starts with AGS.

Import the header and the source file (the header is the .h and the source file is the .cpp) into the project.

In MSVC++ this will compile out of the box with no editing. Try and compile it. If it compiles and produces a .dll file in the 'Debug' folder of your project folder then you are good to start coding.

Defining the struct!

Near the top of the source file you will find a section that looks like this:

Code: ags

const char *ourScriptHeader =
	"//script header for plugin\r\n"
	"//This is my script header\r\n";


This is the header that we will give to AGS. The syntax used is just AGS script so you can put anything in here that you could put in AGS script.
the '\r\n' parts just tell the compiler that its a new line. Look up 'Escape Characters' for more information.

Ok so lets define the simple struct that we are going to be making:

Code: ags

const char *ourScriptHeader =
	"managed struct Point2D {\r\n"
	"		import attribute int X;\r\n"
	"		import attribute int Y;\r\n"
	"		import void Add(Point2D *toAdd);\r\n"
	"		import void Subtract(Point2D *toSub);\r\n"
	"       import static Point2D* Create(int X, int Y);\r\n"
	"};\r\n";


Let's go line by line.

The first line of the struct definition tells AGS that its a *managed* struct called Point2D
The second and third lines define 'attributes' X and Y. Attributes are variables with accessors functions so they are got and set by functions in the script and not directly. (I'll show you how later)
The fourth and fifth lines define new functions for us to use. Notice that they take a single variable which is another Point2D pointer.
The sixth line defines a static function called create which allows us to create a new instance of our struct. AGS doesnt allow dynamic creation of managed objects from within the script so we have to use a function in C++ to create one for us and then return he whole struct to AGSScript.
And the last line just closes the struct, duh.

STRUCT DEFINED! LEVEL UP!

Define our C++ class to handle this

What we have done above just defines the struct in AGS. This is useless to C++. C++ spits on this information and asks for a proper definition. What an asshole.

SO lets do that before it gets violent and starts chucking chairs around.

Right click the project in the Solution Explorer in the top right of your screen and goto Add -> Class. Your screen may look different to mine since I'm using VS Studio not Express.



Now click Add (C++ Class should already be selected)

Enter 'Point2D' (no quotes) into class name and press OK or Next or To Infinity And Beyond! or whatever it asks you to press.. yes I closed the window.

You will be presented with a new source file and a new header file (Point2D.cpp and Point2D.h respectively). Open the header file if it's not already open.

It will currently look like this (or similar):

Code: ags

#pragma once
class Point2D
{
public:
	Point2D(void);
	~Point2D(void);
};


exciting huh.

The header file is just like a struct definition. It defines what the class *is* and what it *does* but not *how* it does it.

Let's define stuff.

Code: ags

#pragma once
class Point2D
{
public:
	Point2D(int x, int y);
	void Add(Point2D *obj);
	void Subtract(Point2D *obj);
	~Point2D(void);
	int X;
	int Y;
};


Ok line by line again:

Line 1: #pragma defines are used internally by the compiler for stuff. This one just tells the compiler to only include this header once.. you can ignore it.
2: This just defines the class name.
3: no, shut up.
4: This is really turning into a c++ primer but basically this means that all the declarations below this line are public and accessable from outside the class.
5: Now we're getting somewhere. This defines the 'constructor' of the class. This is the method which is called every time you make a new instance of this class. Notice there is no return type.
6 & 7: These are methods which will be contained in the class.
8: This is the DEconstructor and it's called everytime an instance of your class dies. YES DIES, YOU MONSTER.
9 & 10: This are variables in your class.
11: Closes the goddamn class.

(Dear C++ developers, Yes I know I could override the + and - operators but that is beyond the scope of this article and also I would have to look it up)

Right so we've defined the class. We should *implement* it now.

Open the Point2D.cpp source file which should look like this (similar):

Code: ags

#include "Point2D.h"

Point2D::Point3D(void)
{
}

Point2D::~Point3D(void)
{
}


#include "Point2D.h" just tells the compiled to include the header file in this class.

The 'Point2D::' parts just mean that what follows are part of the Point2D class.

So let's implement stuff.

Code: ags

#include "Point2D.h"

Point2D::Point2D(int x, int y)
{
	X = x;
	Y = y;
}

void Point2D::Add(Point2D *obj)
{
	X += obj->X;
	Y += obj->Y;
}

void Point2D::Subtract(Point2D *obj)
{
	X -= obj->X;
	Y -= obj->Y;
}

Point2D::~Point2D(void)
{
}


Most of this is self-explanatory but lets look at important things.

Firstly I have changed the constructor to match the definition in the header.

X = x; might look silly but notice that the cases are different.
The capital X refers to the X we defined in the header while the lower case x is the one passed by the constructor.
Basically it means (Make the object's X equal the one i was given).

The other two methods just add (or subtract) the passed object's X & Y values to the classes X & Y values.

The last method is just an empty deconstructor.. we dont have any memory that needs to be released in this class so nothing needs to be done here (look it up in a C++ book)

Including the Point2D files in the main source file

Go back to the main source file and add the following line just after #include "agsplugin.h"

Code: ags

#include "Point2D.h"


This simply includes your Point2D class into the main source file.

Define accessor interfaces

Ok this part is a little tricky so pay attention.

AGS needs two interfaces to interact with your object. Specifically a 'ObjectReader' and a 'ManagedObject' interface.

ManagedObject Interface

Insert this code into your main source file just below the script header:

Code: ags

class ManagedPoint2DInterface : public IAGSScriptManagedObject {
public:
	ManagedPoint2DInterface() {};

	virtual int Dispose(const char *address, bool force) {
		delete address; // free the memory and return 1 to tell AGS we did.
		return 1;
	}
	virtual const char *GetType() {
		return typeName;
	}
	virtual int Serialize(const char *address, char *buffer, int bufsize) {
		
			memcpy(buffer, address, sizeof (Point2D));
			return sizeof(Point2D);
	}

	static const char* typeName;
};

const char* ManagedPoint2DInterface::typeName = "Point2D";
ManagedPoint2DInterface gManagedPoint2DInterface;



This is a new class that derives from IAGSScriptManagedObject. The specifics of the mechanics of this are beyond the scope of this article but lets look at what happens.

The 'Dispose' method is run by AGS whenever an instance of your class has been mercilessly slaughtered once it's gone out of scope.
It passes 2 arguments, *address and force.
*address is simply a pointer to the object that it being destroyed. If you want to do anything to that object then you can cast the pointer to the class and work with it.
force is a bool which tells you whether or not this is your last opportunity to release the memory (on a game restore or something) If it is 'true' then you must delete the pointer or you will have a memory leak.
If you do delete the pointer then you must return 1 if not then return 0.

In the case of our very simple struct we just delete the pointer and return 1.

*GetType returns a pointer to a string with the name of the struct that this interface deals with. In our case it just returns a pointer to a static string "Point2D" which is assigned just after the class.

The Seralize method is where we save our object when the game is saved. Since our object is just a simple type we can just memcpy our object into the buffer provided and return how many bytes we wrote.

The last line defines a global reference to the interface that we can use to actually process our objects.

For most simple types you can copy the code above and just swap out all the names so don't worry if you dont understand the code too much.

ObjectReader Interface

The Reader interface is used to read an object back from the save file when a game is restored. It looks like this:

Code: ags

class ManagedPoint2DReader : public IAGSManagedObjectReader {
public:
	ManagedPoint2DReader() {}

	virtual void Unserialize(int key, const char *serializedData, int dataSize) {
		Point2D *newPoint = new Point2D(0,0);
		memcpy(newPoint, serializedData, sizeof(Point2D));
		engine->RegisterUnserializedObject(key, newPoint, &gManagedPoint2DInterface);
	}
};

ManagedPoint2DReader gManagedPoint2DReader;


This interface is much simpler and just defines a single method which Unserializes your objects from a save file.

The first line of the method creates a pointer to a new Point2D and the next line assigns the serializedData memory to it which effectively loads your Point2D from the save file. AGS does all the hard work for you.
The second line registers the Object with the script engine which allows the scripts to access it again. The 'key' argument ensures that the memory is assigned to the correct pointer in the script.
The last line makes a global reference to the interface that AGS can use to deserialise our custom struct.

Putting it all together

Ok thats all the hard stuff out the way, now we just need to stich all the elements together!

Registering the object with AGS

In the main source file you should find a function called AGS_EngineStartup(IAGSEngine *lpEngine). This function is run, surprisingly enough, when the engine starts up. Add the following line to the end of the function:

Code: ags

engine->AddManagedObjectReader(ManagedPoint2DInterface::typeName, &gManagedPoint2DReader);


This does pretty much what it says. It let's AGS know that there is a new managed object in town and it better make accomodations for it or else shit might go down.

Making Accessor Functions

Just above the AGS_EngineStartup function add the following:

Code: ags

void Point2D_set_X(Point2D* obj, int val) {
	obj->X = val;
}

int Point2D_get_X(Point2D* obj){
	return obj->X;
}

void Point2D_set_Y(Point2D* obj, int val) {
	obj->Y = val;
}

int Point2D_get_Y(Point2D* obj){
	return obj->Y;
}

void AddPoint(Point2D *obj, Point2D* obj2){
	obj->Add(obj2);
}

void SubtractPoint(Point2D *obj, Point2D* obj2){
	obj->Subtract(obj2);
}

Point2D* CreatePoint2D(int X, int Y) {
	Point2D *newPoint = new Point2D(X, Y);
	engine->RegisterManagedObject(newPoint, &gManagedPoint2DInterface); // the second parameter is the ManagedObject interface that is responsible for disposing of the object
	return newPoint;
}


I hope that the first four of those functions are pretty straight forward. They just get or set a value in our Point2D object, a pointer to which is always passed at the first parameter to the function (i named it obj).
The 5th and 6th functions just call the Add and Subtract methods of our class.
The 7th function is our static Create function from the struct. It makes a new Point2D (passing the x and y variables it was given), registers that new object with AGS and tells it how to dispose of that object if it needs to and then returns the constructed point to your ags script.

All good? Excellent.

And FINALLY registering those accessor functions with AGS

The final step is to link our accessor functions with the functions defined in the script which is done in the AGS_EngineStartup function.

Just at the end of that function add the following:

Code: ags

	engine->RegisterScriptFunction("Point2D::Create^2", CreatePoint2D);
	engine->RegisterScriptFunction("Point2D::Add^1", AddPoint);
	engine->RegisterScriptFunction("Point2D::Subtract^1", SubtractPoint);
	engine->RegisterScriptFunction("Point2D::set_X", Point2D_set_X);
	engine->RegisterScriptFunction("Point2D::get_X", Point2D_get_X);
	engine->RegisterScriptFunction("Point2D::set_Y", Point2D_set_Y);
	engine->RegisterScriptFunction("Point2D::get_Y", Point2D_get_Y);


The RegisterScriptFunction method takes two values. The first is the name of the AGS function we are registering which we need to look at in more detail.

Firstly notice the 'Point2D::' part. This tells AGS that the following function is part of the Point2D struct.
The number following the ^ symbol tells AGS how many parameters the function takes *not including* the object itself. For instance the 'Add' function takes the object that the function is acting on plus 1 more (the object to add to it in this case) so we append the function name with ^1.

"What about those get_ and set_ functions? They aren't in our struct. WHAT IS GOING ON!?"
Remember we talked about 'attributes' earlier? This is where they come into play. When you define an attribute AGS will use two magic functions to deal with that attribute. They are called get_varName and set_varName. If i try to retrieve a varible's value like this:

Code: ags

Point2D* p = Point2D.Create(1,1);
Display("%d", p.X); // <--- here


AGS will run the Point2D::get_X method and return whatever value it returns. Likewise if I try and *set* a value it will run the set_X method and pass the value I give to it.
So those funny functions are used internally by AGS to access our values.

And thats it!

Compile and add your plugin to your game and you will have a brand new custom object to play with. Lucky you!

A final word on 'linking'

When you compile your plugin under the default settings it will 'dyamically' link to the libraries used by the MSVC++ compiler.. this isnt ideal since it will mean that your users will need that library installed on their computer. So let's fix that.

Firstly change your compiler to 'Release' (if you're using MSVC++, If you aren't i cant help you). You can do this here:


Yours might look different. Tell me and I'll update the tutorial.

Now right click your project in the Solution Explorer and click Properties.



Change the highlighted setting to "Multi-threaded (/MT)" This will include the basic libraries in with your plugin and save alot of people some trouble.

Recompile and your plugin will now be in the 'Release' folder of your project folder. Changing to Release also heavily optimises your plugins code and doesn't include all the debugging symbols and stuff. So hooray for that.

Have fun*!

*Fun involves C++ programming. Might not actually be fun.

Change History

1.0 - initial

1.1 - Fixed Unserialize method.
#74
So I recently discovered that AGS script allows you to make managed structs using this magic keyword however I am a little confused.

How can we have a managed struct with pointers if we have no way to actually make an instance of the struct? All other pointers in AGS have a static method which returns a pointer to a struct but in the script we can't do this because we would need someway of making a new struct to return which we can't.

The example Ryan Timothy posted in this thread (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=43593.msg580258#msg580258 ) seems to suggest that you can just declare the pointer and the engine will automatically create an empty instance of the struct.. is this how it works? because that seems a little odd to me considering that none of the other pointers behave like that.

I mean what is the intended use of this keyword and why isnt it mentioned in the literature?
#75
General Discussion / Bananas eat fish?
Wed 25/05/2011 08:03:30
Hats have more than one use. Try to think of them all whilst counting backwards from 14. If you get stuck remember to ask an assistant for assistance. If the assistant is unable to assist then they are likely not an assistant but in fact a primrose bursting with colour on a Saturday afternoon. The plural of primrose is dogs which has been the source of confusion for many a scientist throughout the ages attempting to reproduce the effect of mist gently carressing the loch in autumn with her bitter tendrils. A tendril is a kind of hat with many (at least more than one) uses, which is interesting because the telephone is ringing.
#76
I have been coding a more processor intensive game recently and it runs at a full 60fps on my 4 year old core2duo XP laptop.

However on my core2quad Win7 desktop which is only a year or so old it only runs at 50fps. DirectDraw and D3D.

Are there some speed issues with Win7 or newer versions of DirectX?
#77
I have a problem thats need solving and it's already pretty well established that my mathematical abilities are poor to say the least so I thought I would outsource this one to people who actually went to school.

Consider the following:

I have a tile height map which is arranged as an array of integers with a range of 0-2 (0 being ground level)

There is a character stood on 1 of these tiles who has a set number of 'movement points'
To travel to an adjacent (non-diagonal) tile of equal or less height to the current tile costs 1 movement point.
To travel to an adjacent (non-diagonal) tile with a height of 1 greater than the current tile costs 2 movement points.
The character cannot travel (directly) to an adjacent tile if the destination tile has a height of 2 greater than the current tile.

My question is how can i determine (by populating a boolean mask array) which tiles a character can move to?

Supplementary question:

If I were to calculate the best route to any of the tiles to which the character can move (as established in question 1) what would be the best way to do that observing all the conditions above.
#78


(placeholder gfx)

Ok so lets assume there is a sprite sat on one of these iso tiles. How could i tell (mathematically if possible rather than drawing function) if an individual pixel of that sprite is visible and not hidden behind a higher tile in front of it?
#79
General Discussion / Voting time!
Wed 04/05/2011 21:43:33
So britain is again in voting mode and I was wondering how people planned to vote and what their thoughts are on the AV referendum.

I shall be voting a firm 'yes'
#80
Critics' Lounge / I done recorded a song.
Fri 29/04/2011 01:01:02
I recorded a song cover today. I would like to know what you people think of it.

(blog with player) http://www.thethoughtradar.com/blog/?p=239

(direct link) http://www.thethoughtradar.com/songs/bringhimhome.mp3

merci.
SMF spam blocked by CleanTalk