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 - kanonet

#1
1. On windows SETSCREEN is basically broken. If I use SETSCREEN to change window size, the window gets created in the requested size, but the render area is only of the screen size that is set in project options. So if project options screen size is smaller than SETSCREEN, then there is a black (or other color set with CLEARSCREEN) border, if project settings is bigger than SETSCREEN, part of the screen gets rendered outside of the windo, so its not displayed fully.

2. Fullscreen not working. If I set fullscreen using SETSCREEN, I just get a fullscreen blackscreen, nothing is displayed. Setting fullscreen in project settings just gets ignored and does nothing changes, it gets rendered normally in windowed mode.


All tests only done on windows, no idea about other platforms.
#2
I did play around with shaders in last time and got some nice effects for the beginning. But it would be really useful if we could get some more feature to use them better/ more properly:

1. X_PUTSHADER needs to get extended to store other data types like:
GLB -> glsl shader
DGInt -> float (only thing that currently works)
array[2] -> vec2
array[3] -> vec3
array[4] -> vec4
array[9] -> mat3
array[16] -> mat4
sprite ID -> sampler2D (i need a way to input more textures/ offscreen buffers)
[ TYPE (of DGInts) -> C struct (of floats) ]
Cause its very much work (and a dirty work around) to break everything into many floats and pass each float on its own into the shader. We can not do this with INLINE on our own atm.

2. Extend X_GETCAMERAMATRIX (with optional parameter, or create a new command?) so that it can output each of the matrix:
modelviewmatrix
projectionmatrix
[texturematrix]
Yes we can do this with INLINE on our own, but Im not sure if it will work on all platforms. So a native solution would be awesome.


I understand that this are advanced features and that GLB is designed to be easy - but since I do not request to remove any feature, it will not get harder for anyone. Btw. i do not need to get these functions directly in GLB, it would be totally ok, if there were some easy to use C functions that we can use with INLINE on ALL platforms. Thank you for you work Kitty!
#3
If you use REDIM [0] to 'delete' an integer array, array.count gets not updated, so FOREACH thinks the array is still big and calls the deleted entries too. LEN and BOUNDS work correct. The bug only happens with integer arrays and when you REDIM it to [0], all other values work fine, so do arrays of floats, string and types. I did only test V11.

Here is an example:
Code (glbasic) Select
LOCAL a%[]
DIM a[4]
FOR i%=0 TO a.count-1
a[i]=i
NEXT
REDIM a[0]
DEBUG "count: "+(a.count)+"  len: "+LEN(a[])+"  bounds: "+BOUNDS(a[],0)+"\n"
DEBUG "elements with foreach:\n"
FOREACH b IN a[]
DEBUG b+"\n"
NEXT
DEBUG "elements with for:\n"
FOR i%=0 TO LEN(a[])-1
DEBUG a[i]+"\n"
NEXT

This is the output that i get from this example:
Code (glbasic) Select
count: 4  len: 0  bounds: 0
elements with foreach:
0
1
2
3
elements with for:


BTW. did I win a prize for finding the most exotic bug in the new year? :D
#4
Ok i just found something really wired regarding to speed of GLB:
Code (glbasic) Select
LOCAL start=0
LOCAL stop=200000
LOCAL stepping=0.005

time0=GETTIMERALL()
FOR i=start TO stop STEP stepping
value=1
NEXT
time0=GETTIMERALL()-time0
PRINT time0+" ms", 0,0

Displayed time after execution: about 89 ms

Code (glbasic) Select
LOCAL start=0
LOCAL stop=200000
LOCAL stepping=0.005

time0=GETTIMERALL()
FOR i=start TO stop STEP stepping
value=1
NEXT
time0=GETTIMERALL()-time0
LOCAL s$=value
PRINT time0+" ms", 0,0

Displayed time after execution: about 112 ms

Im checking time for exactly the same code in both cases, but its significant slower if i convert the result to a string in an other part of the program (displaying the result with PRINT has the same effect). Does anyone has an idea why this happens?
#5
Introduction:
If you ever wanted to be able to rotate X_SPRITEs or you want them to be faster (so you can create plenty of them, e.g. for a particle engine), than here is a solution for you:
My TSprite can get scaled, rotated and positioned anywhere in the 3D-scene, it will always turn to the camera (like X_SPRITE does), even if you use X_CAMERAUP (for a 6DOF camera). Its all encapsulated into one Type, for easy transfer to your projects. I tested this lib on Windows, Linux and Android, its all working perfectly and I know no reason why it should not work on any other major platform.

You can find newest libQMATH here: http://www.kanonet.de/downloads/libqmath
You always find the latest version on my website: http://www.kanonet.de/downloads/libsprite


Comparison with X_SPRITE:
differences:
  • its midhandled (centered)
  • need to get textured manually
  • scale=1 has alwasy the same size (1 unit in 3D environment), no matter what size the texture got
advantages:
  • rotation is possible
  • can draw two different types of billboards:
    • draw()   -> spherical billboard, same like x_sprite, but with rotation
    • draw2() -> cylindrical billboard, use it for trees etc., can rotate too
  • faster at least +5-400% on my machine (without texture ordering)
  • gives you the ability for texture ordering (+700-3200% more speed on my machine!  :O)
  • you can set texture coordinates, so you can draw all sprites from one single texture atlas!
disadvantages:
  • you need to call more than one function
  • my libQMATH is needed in your project


How to use it:
At game start, define the type:
Code (glbasic) Select
LOCAL sprite AS TSprite
In your gameloop render all your GLB 3D stuff, than call sprite.Start(), draw your sprites and texture them, try to use as few X_SETTEXTURE as possible if some sprites use the same texture, just make only one X_SETTEXTURE and draw all sprites that use it (texture ordering). You can call SetTextureCoords() to use a sprite Atlas (and avoid calls for X_SETTEXTURE)! End your sprite drawing with sprite.Stop(). Just use one Start() and Stop() pair each loop and draw all sprites between them. Do not use any GLB OpenGL calls between Start() and Stop()!
Code (glbasic) Select
sprite.Start()
X_SETTEXTURE 0
sprite.Draw()
sprite.Draw()
sprite.Draw2()
sprite.SetTextureCoords()
sprite.Draw()
sprite.Draw2()
X_SETTEXTURE 1
sprite.Draw()
X_SETTEXTURE 2
sprite.Draw()
sprite.Draw2()
sprite.Stop()



Code:
Code (glbasic) Select
// ------------------------------------------ //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: August 22, 2015
// For a newer Version go to: http://www.kanonet.de/downloads/libsprite
// ------------------------------------------ //

TYPE TSprite
INLINE
namespace libSPRITE {
typedef unsigned int    GLenum;
typedef void            GLvoid;
typedef int             GLint;
typedef int             GLsizei;
typedef float           GLfloat;
#ifdef __WIN32__
#ifndef APIENTRY
#define APIENTRY __stdcall
#endif
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#endif
const GLint GL_TRIANGLE_STRIP = 0x0005;
const GLint GL_FLOAT = 0x1406;
const GLint GL_VERTEX_ARRAY = 0x8074;
const GLint GL_TEXTURE_COORD_ARRAY = 0x8078;
extern "C" {
void APIENTRY glNormal3f( GLfloat nx , GLfloat ny , GLfloat nz );
void APIENTRY glColor4f( GLfloat red , GLfloat green , GLfloat blue , GLfloat alpha );
void APIENTRY glEnableClientState( GLenum cap ); /* 1.1 */
void APIENTRY glDisableClientState( GLenum cap ); /* 1.1 */
void APIENTRY glVertexPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void APIENTRY glTexCoordPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void APIENTRY glDrawArrays( GLenum  mode,  GLint  first,  GLsizei  count );
}
struct TSpriteContainer {
float texcoord[8];
float vertices[12];
float m0, m1, m2;
float m4, m5;
float m8, m9, m10;
float normalx, normaly, normalz;
int lastnum;
} static TSpr = { {0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.0f} };
}
ENDINLINE

// start drawing of sprites, call it one time  each loop, before you draw your sprites and call Stop() when you did draw all your sprites
// do not use any normal GLB OpenGL between Start() and Stop()!
FUNCTION Start%:
STATIC mat#[]
X_GETCAMERAMATRIX mat[]
INLINE
using libSPRITE::TSpr;
TSpr.lastnum = 0;
TSpr.normalx = mat(2);
TSpr.normaly = mat(6);
TSpr.normalz = mat(10);
TSpr.m0  =  -mat(0);
TSpr.m4  =  -mat(4);
TSpr.m8  =  -mat(8);
TSpr.m1  =  mat(1);
TSpr.m5  =  mat(5);
TSpr.m9  =  mat(9);
TSpr.m10 =  qInvSQR(TSpr.normalx*TSpr.normalx + TSpr.normalz*TSpr.normalz);
TSpr.m2  =  TSpr.normalx*TSpr.m10;
TSpr.m10 *= TSpr.normalz;
libSPRITE::glEnableClientState( libSPRITE::GL_VERTEX_ARRAY );
libSPRITE::glEnableClientState( libSPRITE::GL_TEXTURE_COORD_ARRAY );
libSPRITE::glTexCoordPointer( 2, libSPRITE::GL_FLOAT, 0, &TSpr.texcoord );
libSPRITE::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
ENDINLINE
ENDFUNCTION

// draw a spherical sprite (same like X_SPRITE)
// needs to be after Start() [and before Stop()]
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw%: x AS float, y AS float, z AS float, scale#=1.0, rotation#=0.0
INLINE
using libSPRITE::TSpr;
scale *= 0.5;
float rc = qSIN( rotation + 90 ) * scale;
float rs = qSIN( rotation      ) * scale;

float rot = TSpr.m1 * rs + TSpr.m0 * rc;
float xp  = TSpr.m1 * rc - TSpr.m0 * rs;
float xn  = rot-xp;  xp += rot;
TSpr.vertices[0] = x + xp;  TSpr.vertices[3] = x - xn;  TSpr.vertices[6] = x + xn;  TSpr.vertices[9] = x - xp;

rot = TSpr.m5 * rs + TSpr.m4 * rc;
xp  = TSpr.m5 * rc - TSpr.m4 * rs;
xn  = rot-xp;  xp += rot;
TSpr.vertices[1] = y + xp;  TSpr.vertices[4] = y - xn;  TSpr.vertices[7] = y + xn;  TSpr.vertices[10]= y - xp;

rot = TSpr.m9 * rs + TSpr.m8 * rc;
xp  = TSpr.m9 * rc - TSpr.m8 * rs;
xn  = rot-xp;  xp += rot;
TSpr.vertices[2] = z + xp;  TSpr.vertices[5] = z - xn;  TSpr.vertices[8] = z + xn;  TSpr.vertices[11]= z - xp;

if (TSpr.lastnum != 1) {
libSPRITE::glNormal3f( TSpr.normalx, TSpr.normaly, TSpr.normalz );
TSpr.lastnum = 1;
};
libSPRITE::glVertexPointer( 3, libSPRITE::GL_FLOAT, 0, TSpr.vertices );
libSPRITE::glDrawArrays( libSPRITE::GL_TRIANGLE_STRIP, 0, 4 );
ENDINLINE
ENDFUNCTION

// draw a cylindrical sprite (same like X_SPRITE)
// needs to be after Start() [and before Stop()]
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw2%: x AS float, y AS float, z AS float, scale#=1.0, rotation#=0.0
INLINE
using libSPRITE::TSpr;
scale *= 0.5;
float rc = qSIN( rotation + 90 ) * scale;
float rs = qSIN( rotation      ) * scale;

float rot = TSpr.m10 * rc;
float xn  = TSpr.m10 * rs;
float xp  = rot-xn;  xn += rot;
TSpr.vertices[0] = x - xp;  TSpr.vertices[3] = x + xn;  TSpr.vertices[6] = x - xn;  TSpr.vertices[9] = x + xp;

TSpr.vertices[1] = y + rs + rc;  TSpr.vertices[4] = y - rs + rc;  TSpr.vertices[7] = y + rs - rc;  TSpr.vertices[10]= y - rs - rc;

rot = TSpr.m2 * rc;
xn  = TSpr.m2 * rs;
xp  = rot-xn;  xn += rot;
TSpr.vertices[2] = z + xp;  TSpr.vertices[5] = z - xn;  TSpr.vertices[8] = z + xn;  TSpr.vertices[11]= z - xp;

if (TSpr.lastnum != 2) {
libSPRITE::glNormal3f( TSpr.m2, 0.0f, TSpr.m10 );
TSpr.lastnum = 2;
};
libSPRITE::glVertexPointer( 3, libSPRITE::GL_FLOAT, 0, TSpr.vertices );
libSPRITE::glDrawArrays( libSPRITE::GL_TRIANGLE_STRIP, 0, 4 );
ENDINLINE
ENDFUNCTION

// use this if you want to change texture coords
// its way faster to change texture coords instead of changing texture with X_SETTEXTURE
// it will affect all following draw()/draw2() calls, in all following loops!
// default is (0,1, 1,1, 0,0, 1,0)
FUNCTION SetTextureCoords%: t0x AS float, t0y AS float, t1x AS float, t1y AS float, t2x AS float, t2y AS float, t3x AS float, t3y AS float
INLINE
using libSPRITE::TSpr;
TSpr.texcoord[0] = t0x; TSpr.texcoord[1] = t0y;
TSpr.texcoord[2] = t1x; TSpr.texcoord[3] = t1y;
TSpr.texcoord[4] = t2x; TSpr.texcoord[5] = t2y;
TSpr.texcoord[6] = t3x; TSpr.texcoord[7] = t3y;
ENDINLINE
ENDFUNCTION

// call it after you did draw all your sprites
// its not totally necessary to use this function, but strongly recommended
FUNCTION Stop%:
INLINE
libSPRITE::glDisableClientState( libSPRITE::GL_TEXTURE_COORD_ARRAY );
libSPRITE::glDisableClientState( libSPRITE::GL_VERTEX_ARRAY );
ENDINLINE
ENDFUNCTION

ENDTYPE



Test Program:
Code (glbasic) Select
// --------------------------------- //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: September 06, 2013

SETSCREEN 800,600,0
SYSTEMPOINTER TRUE
ALLOWESCAPE FALSE
AUTOPAUSE FALSE
LIMITFPS -1

// number of sprites to draw:
LOCAL count%=1000

LOCAL root%=SQR(count)/2, line%, row%, fps, timer, mx%, my%=15, mz=-4, selected%=1, rot%

// texture
CREATESCREEN 0, 0, 16,16
USESCREEN 0
DRAWRECT 0,0, 16, 16, RGB(0,0,255)
DRAWRECT 12,0, 4,8, RGB(255,127,0)
DRAWRECT 0,12, 4,4, RGB(255,0,63)
DRAWLINE 0,0, 16,16, 0xffffff
DRAWLINE 0,16, 16,0, 0xffffff
USESCREEN -1
CREATESCREEN 0,-1,0,0

// sprite
LOCAL sprite AS TSprite

// mainloop
REPEAT

line=-root; row=-root; INC rot

// mouse for camera control:
mx = mx + MOUSEAXIS(0)
my = my + MOUSEAXIS(1)
mz = mz + MOUSEAXIS(2)
IF KEY(27) // + more sprites
INC count
root=SQR(count)/2
ENDIF
IF KEY(53) AND count>1 // - less sprites
DEC count
root=SQR(count)/2
ENDIF
IF KEY(2) THEN selected=1
IF KEY(3) THEN selected=2
IF KEY(4) THEN selected=3

X_MAKE3D 0.1, 1000, 45
X_CAMERA my*COS(mx)*root*0.2,mz*2,my*SIN(mx)*root*0.2, 0,0,0

X_DRAWAXES 0,0,0
X_CULLMODE 1

LOCAL cx=my*COS(mx)*root*0.2, cy=mz*2, cz=my*SIN(mx)*root*0.2

IF selected=1
FOR i=1 TO count

X_SPRITE 0, 0, line, row, 0.06

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
ELSEIF selected=2
sprite.Start()
FOR i=1 TO count

X_SETTEXTURE 0, -1
sprite.Draw(0, line, row, 0.5)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ELSE
sprite.Start()
X_SETTEXTURE 0, -1
FOR i=1 TO count

sprite.Draw(0, line, row, 0.5)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ENDIF

X_MAKE2D
ALPHAMODE 0.9
DRAWRECT 0,0,800,60,RGB(70,70,70)
PRINT "CAMERA CONTROL: MOVE MOUSE / MOUSE WHEEL    |    FPS: "+INTEGER(1000/(timer-fps)), 0,0
PRINT "SPRITES CURRENTLY: "+count+"    |    PRESS (+) FOR MORE SPRITES AND (-) FOR LESS", 0,15
PRINT "SELECT: (1) X_SPRITE    |    (2) TSPRITE    |    (3) TSPRITE WITH TEXTURE ORDERING", 0, 30
PRINT "SELECTED: "+selected, 0, 45

LOCAL b1%, b2%
MOUSESTATE mx, my, b1, b2
PRINT "v",mx,my
DRAWRECT 80,80,20,20,RGB(255,127,127)
PRINT "0", 90,90
IF mx>80 AND mx<100 AND my>80 AND my<100 AND b1 THEN selected=1
DRAWRECT 110,80,20,20,RGB(255,127,127)
PRINT "1", 120,90
IF mx>110 AND mx<130 AND my>80 AND my<100 AND b1 THEN selected=2
DRAWRECT 140,80,20,20,RGB(255,127,127)
PRINT "2", 150,90
IF mx>140 AND mx<160 AND my>80 AND my<100 AND b1 THEN selected=3

SHOWSCREEN
  fps=timer
timer=GETTIMERALL()
UNTIL KEY(1)
END



Finally some test results (FPS), done on my T410s (see signature), which have two graphiccards (i can select one to use):
Intel HD Graphics - 1000 Sprites: 46 / 48 / 393
Intel HD Graphics - 2000 Sprites: 24 / 25 / 253
Intel HD Graphics - 3000 Sprites: 16 / 17 / 196
Intel HD Graphics - 4000 Sprites: 12 / 13 / 152
Intel HD Graphics - 5000 Sprites: 10 / 10 / 125
Intel HD Graphics - 7500 Sprites: 7 / 7 / 88
Intel HD Graphics - 10000 Sprites: 5 / 6 / 68
NVidia NVS 3100M - 1000 Sprites: 85 / 459 / 500 (cant do more)
NVidia NVS 3100M - 2000 Sprites: 50 / 256 / 500 (cant do more)
NVidia NVS 3100M - 3000 Sprites: 35 / 175 / 500 (cant do more)
NVidia NVS 3100M - 4000 Sprites: 27 / 134 / 500 (cant do more)
NVidia NVS 3100M - 5000 Sprites: 22 / 110 / 500 (cant do more)
NVidia NVS 3100M - 7500 Sprites: 15 / 74 / 480
NVidia NVS 3100M - 10000 Sprites: 11 / 56 / 370
#6
DD-GUI / DDcreator
2012-Feb-28
If you like using DDgui in you project, but dont like to code the gui manually, this is what you need! You can just click your gui together and edit/position your widgets fast. If your gui is complete, just save it into a file. You still need to know how DDgui works, but it will save you some time and make it easier to create your gui.
Its all written in GLBasic and DDgui, so you can run it on any platform and expand it easily. If you fix some bugs, or add some features, please share them with use! ;)

How to use:
  • download and unzip the code
  • add a current version of "DDgui.gbas" (better always use a actual one)
  • compile and run program
  • you will see two windows, in the smaller one you can create and edit the gui, in the other one you see the result (this window is really just for showing you the result, any changes that you make here will get lost!)
  • create your gui ;)
  • hit the "save into file" button (code will get stored into "Form.gbas")
  • copy the gui code from "From.gbas" into your project and be happy :P

Screenshots:
       

If you like this or have any suggestions/question/criticism, please give me feedback.

Regards,
Kanonet

You always find the latest version on my website: http://www.kanonet.de/downloads/ddcreator

[attachment deleted by admin]
#7
SOCK_TCPACCEPT( sock%, ip% )
ip% = SOCK_GETREMOTEIP( sock% )
In beiden fällen ist ip% immer 0.
Das Netzwerk funktioniert, ich kann empfangen und senden, wie es sein soll, es ist mir lediglich nicht möglich die IP des Clients/Servers zu ermitteln. Betrifft TCP, sowohl wenn sich Client und Server auf einen Rechner befinden, als auch, wenn sie auf verschiedenen laufen. Nicht getestet unter UDP.

EDIT: Auch zum Thema SOCK_...:
Interessanterweise habe ich gerade festgestellt, dass bei Kommunikation zwischen zwei Rechnern meine Firewall (Comodo) verhindert, dass ich feststellen kann, dass die Verbindung abgebrochen ist. Wenn der Client offline gegangen ist, erhält der Server über SOCK_RECV weiterhin -2 als Rückgabewert, statt der erwarteten und gewünschten 0. Irgendeine Idee, wie dies gelöst werden kann, ohne die Firewall zu deaktivieren?
#8
Ja, wie funktioniert REDIM eigentlich intern? Ich weiß, wie es einzusetzen ist, aber ich möchte gern wissen, wie es intern arbeitet, damit ich geschwindigkeitsabhängige Vorgänge noch besser optimieren kann.

Wenn ich schreibe:
Code (glbasic) Select
LOCAL a%[], b%[]

DIM a[100]
REDIM a[0]

REDIM b[100]

Würde dann b[] den nicht freigegebenen Speicher von a[] nutzen, oder könnte das ausschließlich a[] selbst? Und falls b[] dazu in der Lage wäre, wie sieht es aus, wenn a[] und b[] sich in verschiedenen Types, Functionen, Subs,... befinden?
Ich weiß nicht, ob dies außer Gernot jemand beantworten kann, auf jeden Fall bedanke ich mich für eure Hilfe.

Grüße.

EDIT: weil ich gerade dabei bin:
Es wäre sehr nützlich, wenn man FOREACH um ein optionales STEP -1 oder ähnliches erweitern könnte, damit man ein Array rückwärts durchsuchen kann, ohne auf die Geschwindigkeit von FOREACH verzichten zu müssen.

EDIT2: wieso gibt das folgende keinen Fehler/Programmcrash?:
Code (glbasic) Select
DIM a[1]
WHILE a[-1]=0
DIMDEL a[], -1
WEND
#9
Drückt man in laufendem Programm F10, wird das Programm so lange angehalten, bis wieder eine Taste gedrückt wird. Tritt sowohl im Debug, als auch im Releasemodus auf (sowohl in V9, als auch in V10), jedoch nur im Fenstermodus. Ist das ein Feature?
#10
Ich hätte ein paar Änderungsvorschläge:

1. Wenn man bei einem GLBasic-Befehl F1 drückt kommt man zur zugehörigen Hilfeseite, drückt man bei einer eigenen Funktion/Sub F1 wird jedoch nur die Hilfe (mit der aktuell geöffneten Seite) nach vorn geholt.
Ich hätte gern, dass wenn ich beim Nutzen einer eigenen Funktion F1 drücke, der Cursor automatisch zur Funktionsdeklaration springt. Sollte natürlich auch bei Funktionen funktionieren, die in anderen .gbas Dateien deklariert wurden.

2. Befindet sich der Curser auf einem Funktionsnahmen erscheint dieser ja unten links mit seinen Parametern und eventuellen Kommentaren. Gibt es jedoch in mehreren Types gleichnamige Funktionen, wird immer die zuerst erstellte (?) angezeigt, auch wenn es sich eigentlich um eine andere handelt, was im Falle unterschiedlicher Parameter verwirrend sein kann. Es wäre natürlich angenehmer, wenn immer die aktuell verwendete Angezeigt werden würde, jedoch vermute ich, dass dies zu aufwändig zu implementieren wäre? Wobei dieser Punkt auch für die Umsetzung von 1. relevant ist...

3. Ich speichere gern Optionen und ähnliches in .ini-Dateien, welche ich dabei auch gern in der IDE öffne. nehme ich jetzt lediglich Änderungen in der Ini vor und drücke dann F5, wäre es wünschenswert, dass die IDE die Ini zwar speichert jedoch den Code nicht erneut compiliert (ist ja nicht nötig, da keine Änderungen vorgenommen wurden) sondern die .exe sofort startet. Sollte natürlich nicht nur für Inis, sondern sämtliche nicht .gbas (oder .gbap) Dateien so sein.

Gibt es eigentlich mittlerweile eigentlich die geplante (optional aktivierbare) Autovervollständigung?

Wäre schön, wenn das eine oder andere umgesetzt werden könnte, vielen Dank.
Grüße
#11
I created my own simple "key"-management, for user defined keys. A "key" can be a key from keyboard, mousemovement, mousebutton, joystickmovement or joystickbutton, you dont have to care about what the player use, the key-management will do all on its own. Keyboardlayouts are stored in .ini-files, i created one for us/uk and one for german keyboard, but of cause you can convert/create others for other countries (please share them with us/me!).

Its really simple to use:
1. create a new key:
Code (glbasic) Select
LOCAL attack AS Tkey

2. let the player define his key:
Code (glbasic) Select
REPEAT
PRINT "Define control for attack",0,0
SHOWSCREEN
UNTIL attack.SET()
or autoset it (usefull if you load keysettings from a ini-file):
Code (glbasic) Select
attack.SET(1, 57)and you can add a secondary/alternativ key:
Code (glbasic) Select
attack.SET(2) or attack.SET(2, 28)

3. in your mainloop, check whether the player use the key:
Code (glbasic) Select
IF attack.DOWN() THEN DOSOMETHING()This checks primary and secondary key.


TKey now informs you about keyup/-down event.:
//  0 = not pressed / nicht gedrückt
//  2 = just pressed / gerade runtergedrückt
//  1 = pressed / gedrückt (gehalten)
// -1 = release event / wieder losgelassen
Of cause it only works, if you use DOWN() in your loop...


The ini-files for us and german keyboard are attached, here is the code for the key-management:
Code (glbasic) Select
// --------------------------------- //
// Project: MyKey
// Autor: kanonet
// Start: Tuesday, February 08, 2011
// Last Update: December 6, 2012

GLOBAL KEY_mouse_sensitivity% = 2 // sensitivity of the mouse
GLOBAL KEY_joystick_sensitivity# = 0.35 // sensitivity of the joystick
GLOBAL KEY_keymap$[]
GLOBAL KEY_joystick_count% // for intern use, do not change
GLOBAL KEY_ini_file$ = "keymap_us.ini" // which INI file to read for keyboard layout


//! Type of a "key". It is possible to set a primary and a secondary "key".
//! "key" can be a key of the keyboard, a mousemovement, a mousebutton, a joystickmovement or a joystickbutton.
//! After a "key" was set with SET(), you can use DOWN() to check whether the player use it.
//? Typ eines "keys". Es ist möglich einen primären und einen sekundären "key" zu festzulegen.
//? "key" kann eine Taste der Tastatur, eine Mausbewegung, ein Mausbutton, eine Joystickbewegung oder ein Joystickbutton sein.
//? Nachdem ein "key" mit SET() gestzt wurde, kann mit DOWN() geprüft werden, ob er benutzt wird.
TYPE Tkey
code% // eventcode of the "key" if "key" is on the keyboard, code = scancode of the key
name$
code2%
name2$
state%

//! Initialise/sets the "key". Can get used as often as its needed, until played sets a "key".
//! You can change the "key" as often, as you want. You can define a alternativ "key" also.
//? Initialisiert/setzt den "key". Kann beliebig oft aufgerufen werden, bis der Spieler einen "key" gesetzt hat.
//? Ein gesetzter "key" kann beliebig oft geändert werden. Es kann außerdem auch ein alternativer "key" definiert werden.
// \param num% - Optional, use function call to set the primary (num%=1) or secondary (num%=2) "key". | Optional, mit funltionsaufruf wird der primäre (num%=1) oder der sekundäre (num%=2) "key" festgelegt.
// \param code% - Optional, only use this if you want to select a "key", not the player!  | code% - Optional, sollte nur genutz werden, wenn man selbst ein "key" setzen und dies nicht den Spieler überlassen will!
// \return 0 if no "key" was set, otherwise code% of the "key". | 0 wenn kein "key" gesetzt wurde, ansonsten code% des gesetzten "keys".
FUNCTION SET: num%=1, code%=0

LOCAL event%, name$
event=code

IF NOT code // only check for userinput if no key was specified

// check Keyboard
FOR i=1 TO 237
IF i=89 THEN i=153
IF KEY(i)
event=i; BREAK
ENDIF
NEXT


IF NOT event

// check mouse
IF MOUSEAXIS(3); event=331
ELSEIF MOUSEAXIS(4); event=332
ELSEIF MOUSEAXIS(5); event=333
ELSEIF MOUSEAXIS(0)<-KEY_mouse_sensitivity; event=301
ELSEIF MOUSEAXIS(0)>KEY_mouse_sensitivity; event=302
ELSEIF MOUSEAXIS(1)<-KEY_mouse_sensitivity; event=311
ELSEIF MOUSEAXIS(1)>KEY_mouse_sensitivity; event=312
ELSEIF MOUSEAXIS(2)>0; event=321
ELSEIF MOUSEAXIS(2)<0; event=322
ELSE
// check joystick
KEY_joystick_count%=GETNUMJOYSTICKS()-1
FOR i=0 TO KEY_joystick_count
IF GETJOYX(i)<-KEY_joystick_sensitivity; event=401+i*100; BREAK
ELSEIF GETJOYX(i)>KEY_joystick_sensitivity; event=402+i*100; BREAK
ELSEIF GETJOYY(i)<-KEY_joystick_sensitivity; event=411+i*100; BREAK
ELSEIF GETJOYY(i)>KEY_joystick_sensitivity; event=412+i*100; BREAK
ELSEIF GETJOYZ(i)<-KEY_joystick_sensitivity; event=421+i*100; BREAK
ELSEIF GETJOYZ(i)>KEY_joystick_sensitivity; event=422+i*100; BREAK
ELSEIF GETJOYRX(i)<-KEY_joystick_sensitivity; event=403+i*100; BREAK
ELSEIF GETJOYRX(i)>KEY_joystick_sensitivity; event=404+i*100; BREAK
ELSEIF GETJOYRY(i)<-KEY_joystick_sensitivity; event=413+i*100; BREAK
ELSEIF GETJOYRY(i)>KEY_joystick_sensitivity; event=414+i*100; BREAK
ELSEIF GETJOYRZ(i)<-KEY_joystick_sensitivity; event=423+i*100; BREAK
ELSEIF GETJOYRZ(i)>KEY_joystick_sensitivity; event=424+i*100; BREAK
ELSEIF GETDIGIX(i)<-KEY_joystick_sensitivity; event=431+i*100; BREAK
ELSEIF GETDIGIX(i)>KEY_joystick_sensitivity; event=432+i*100; BREAK
ELSEIF GETDIGIY(i)<-KEY_joystick_sensitivity; event=441+i*100; BREAK
ELSEIF GETDIGIY(i)>KEY_joystick_sensitivity; event=442+i*100; BREAK
ELSE
FOR j=0 TO 31
IF GETJOYBUTTON(i, j); event=451+j+i*100; BREAK; ENDIF
NEXT
ENDIF
NEXT
ENDIF

ENDIF

ENDIF

// DIM array for the keyboardlayout
IF KEY_keymap_Str.count <> 324
DIM KEY_keymap$[324]
LOCAL j=0
INIOPEN KEY_ini_file$

FOR i%=0 TO 452
IF i=238
i=301
ELSEIF i=334
i=400
ENDIF
KEY_keymap$[j]=INIGET$("keymap", i, "")
INC j
NEXT
INIOPEN ""
ENDIF

// give readable names
SELECT event
CASE 0 TO 237; name$=KEY_keymap$[event]
CASE 301 TO 333; name$=KEY_keymap$[event-63]
CASE 401 TO (KEY_joystick_count*100+482)
code=MOD(event,100)
name$=GETJOYNAME$(event/100-4)
IF name$="" THEN name$=KEY_keymap$[271]+FORMAT$(2,0,event/100-3)
SELECT code
CASE 1 TO 42; name$=name$+" "+KEY_keymap$[code+271]
CASE 51 TO 82; name$=name$+" "+KEY_keymap$[322]+(code-50)
ENDSELECT
DEFAULT; name$=KEY_keymap$[323]
ENDSELECT

// write the key on specified slot
IF num=2
IF event=self.code
event=0
name$=KEY_keymap$[0]
ENDIF
self.code2%=event
self.name2$=name$
ELSE
IF event=self.code2
event=0
name$=KEY_keymap$[0]
ENDIF
self.code%=event
self.name$=name$
ENDIF
RETURN event

ENDFUNCTION

//! Detect whether a "key" is used by the player or not.
//? Ermittelt ob ein "key" vom Spieler genutzt wird.
// \return 0 if "key" is not in use, otherwise >0. (if "key" is mouse or joystick movementspeed will be returned)  | 0 wenn "key" nicht genutzt wird, ansonsten >0. (ist "key" Maus oder Joystick, wird die Bewegungsgeschwindigleit zurück gegeben)
// \return TKey.state% will tell you, if key was used before: 0=not pressed, 2=just pressed, 1=pressed, -1=release event. | TKey.state% gibt zurück, ob key genutzt wurde: 0=nicht gedrückt, 2=gerade runtergedrückt, 1=gedrückt (gehalten), -1=wieder losgelassen.
FUNCTION DOWN:

STATIC joy, event%, KEY_joystick_sensitivity=0.2
FOR i=0 TO 1
IF i=0
event=self.code
ELSE
event=self.code2
ENDIF

SELECT event
CASE 0; joy=0
CASE 1 TO 237 // check keyboard
joy=KEY(event)
CASE 301 TO 350 // check mouse
SELECT event
CASE 301; joy=MOUSEAXIS(0)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
CASE 302; joy=MOUSEAXIS(0)/20.; IF joy<0 THEN joy=0
CASE 311; joy=MOUSEAXIS(1)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
CASE 312; joy=MOUSEAXIS(1)/20.; IF joy<0 THEN joy=0
CASE 321; joy=MOUSEAXIS(2)>0
CASE 322; joy=MOUSEAXIS(2)<0
CASE 331; joy=MOUSEAXIS(3)
CASE 332; joy=MOUSEAXIS(4)
CASE 333; joy=MOUSEAXIS(5)
ENDSELECT
CASE 401 TO (KEY_joystick_count*100+482) // check joytick
joy=MOD(event,100)
event=event/100-4
SELECT joy
CASE 1; joy=GETJOYX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 2; joy=GETJOYX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 11; joy=GETJOYY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 12; joy=GETJOYY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 21; joy=GETJOYZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 22; joy=GETJOYZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 3; joy=GETJOYRX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 4; joy=GETJOYRX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 13; joy=GETJOYRY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 14; joy=GETJOYRY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 23; joy=GETJOYRZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 24; joy=GETJOYRZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 31; joy=GETDIGIX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 32; joy=GETDIGIX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 41; joy=GETDIGIY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 42; joy=GETDIGIY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 51 TO 82; joy=SGN(GETJOYBUTTON(event, joy-51))
DEFAULT; joy=0
ENDSELECT
DEFAULT; joy=0
ENDSELECT
IF joy THEN BREAK
NEXT
// check if key was used before
IF joy
IF self.state
self.state=1
ELSE
self.state=2
ENDIF
ELSE
IF self.state>0
self.state=-1
ELSE
self.state=0
ENDIF
ENDIF
RETURN joy

ENDFUNCTION

ENDTYPE

Please let me know what you think about this and report bugs. I dont have a real joystick/gamepad (i just used a virtual one) and my keyboard has no numpad/mediakeys, so it would be really nice if someone could test this for me. EDIT: Testing done by Ragaril, thank you!
EDIT2: small Update.
EDIT3: small Update. :P
EDIT4: there was a small typo in last Update. :-[

[attachment deleted by admin]
#12
Ich habe eine kleine Wegfindungsroutine geschrieben, sie basiert auf dem A*-Algorithmus und ermöglicht die Bewegung in acht Richtungen, also auch diagonal. Wegkosten können beachtet werden.
Aus Geschwindigkeitsgründen erfolgt die Wegsuche gleichzeitig vom Start- und dem Zielpunkt aus, was bei großen Karten zu kleineren Abweichungen in der Mitte führen kann.

Zur Benutzung:
Init_FindPath() einmal ausführen, also vor der Hauptschleife.
Advanced_FindPath() kann dann beliebig oft aufgerufen werden.
Parameter sind ähnlich Gernots FINDPATH(). Zu beachten ist noch, dass beide Routinen im Debugmodus signifikant verlangsamt werden, außerdem dauert die Berechnung um so länger, je mehr begehbare Felder es gibt.

Ich habe mich bemüht eine möglichst hohe Geschwindigkeit zu ermöglichen. Ich würde mich freuen, wenn es dem einen oder anderen nützen würde, und/oder ich weitere Verbesserungsvorschläge bekomme, vielleicht findet sich ja jemand in meine Kommentierung hinein. :D

Viele Grüße.

Hier die Routine in einem kleinen Beispiel, wollt ihr sie selbst nutzen, dann einfach die beiden Funktionen kopieren:

EDIT: ein kleiner aber gravierender Fehler wurde korrigiert. Schaut euch aber auch diesen Algorithmus an und entscheidet dann, was eure Bedürfnisse besser erfüllt.
Code (glbasic) Select
// --------------------------------- //
// Project: Wegfindung
// Autor: Kanonet
// Start: Tuesday, October 19, 2010
// Update: July 23, 2011
// IDE Version: 8.125

LOCAL map[] // dies ist die Karte mit der die Wegfindungsrotiene arbeitet
GLOBAL AFP_mapmax_x%, AFP_mapmax_y% // Größe der Karte; wir von Init_FindPath gesetzt

LOCAL x%, y%, zx%, zy%, lger[], lkan[], mx, my, mr, ml, timeger, timekan, mdown

Init_FindPath(map[], 80,60) // Initialisierung der Wegfindung

SETSCREEN AFP_mapmax_x*10, AFP_mapmax_y*10, 0
SYSTEMPOINTER TRUE

x=0
y=2
zx=AFP_mapmax_x-1
zy=AFP_mapmax_y-1


REPEAT

MOUSESTATE mx, my, mr, ml
IF mr // rechte Maustaste -> Startpunkt setzen
x=mx/10
y=my/10
ELSEIF ml // linke Maustaste -> Zielpunkt setzen
zx=mx/10
zy=my/10
ELSEIF MOUSEAXIS(5) OR KEY(56) // mittlere Maustaste -> passierbarkeit dieses Runkts der Karte ändern
IF mdown=0
mdown=-map[mx/10][my/10]
ENDIF
IF KEY(29) OR KEY (157) THEN mdown=5
map[mx/10][my/10]=mdown
ELSE
mdown=0
ENDIF

IF KEY(57) // Wegsuchen starten und benötigte Zeit messen
timeger=GETTIMERALL()
FINDPATH(map[], lger[], 0.5, x, y, zx, zy)
timeger=GETTIMERALL()-timeger
timekan=GETTIMERALL()
Advanced_FindPath(map[], lkan[], 1, x, y, zx, zy)
timekan=GETTIMERALL()-timekan
ENDIF

FOR i=0 TO AFP_mapmax_x-1 // Karte zeichnen
FOR j=0 TO AFP_mapmax_y-1
IF (map[i][j])<=0 THEN DRAWRECT 10*i, 10*j, 10, 10, RGB(255,255,255)
ALPHAMODE 0.5
IF map[i][j]>1 THEN DRAWRECT 10*i, 10*j, 10, 10, RGB(128,128,128+20*map[i][j])
ALPHAMODE 0
NEXT
NEXT

FOR i=1 TO LEN(lger)-1 // Gernots Weg einzeichnen
DRAWLINE 10*lger[i-1][0]+4,  10*lger[i-1][1]+4,  10*lger[i][0]+4,  10*lger[i][1]+4, RGB(255,0,0)
DRAWRECT 10*lger[i][0]+3,  10*lger[i][1]+3, 3, 3, RGB(255,0,0)
NEXT

FOR i=1 TO LEN(lkan)-1 // Kanonets Weg einzeichnen
DRAWLINE 10*lkan[i-1][0]+3,  10*lkan[i-1][1]+3,  10*lkan[i][0]+3,  10*lkan[i][1]+3, RGB(0,255,0)
DRAWRECT 10*lkan[i][0]+2,  10*lkan[i][1]+2, 3, 3, RGB(0,255,0)
NEXT

PRINT "A", 10*x, 10*y // Startpunkt markieren
PRINT "Z", 10*zx, 10*zy // Zielpunkt markieren

PRINT "Gernot: "+timeger+"ms "+LEN(lger)+" Schritte", 0, 0
PRINT "Kanonet: "+timekan+"ms "+LEN(lkan)+" Schritte", 0, 10

PRINT "[SPACE] - Weg suchen         [Maustasten] - Start/Ziel/Karte verändern", 135, 590

SHOWSCREEN

WAIT(20) // Timer

UNTIL KEY(1)
END



//! Timerfunction - NOT NEEDED FOR PATHFINDING!
//! Its just to slow down the program.
//? Timerfunktion - WIRD NICHT FÜR DIE WEGFINDUNG BENÖTIGT!
//? Dient ledglich dazu, dass Programm zu verlangsamen.
// \param ms - Mainloop will last ms milliseconds. | Hauptschleife wird ms Millisekunden dauern.
// \return Nothing. | Nichts.
FUNCTION WAIT: ms
STATIC WAIT_time
WAIT_time = ms - GETTIMERALL() + WAIT_time
IF WAIT_time<0 THEN WAIT_time=0
SLEEP WAIT_time
WAIT_time=GETTIMERALL()
ENDFUNCTION

//! Initialise the pathfinding. Use it once, before your mainloop.
//? Initialisiert die Wegfindung. Muss einmal ausgeführt werden, am besten vor der Hauptschleife.
// \param AFP_map[] - Map that that will be used for pathfinding. | Karte die durch die Weg genutz werden soll.
// \param x,y  - Size of the Map, you want to create. | Größe der Karte, die erzeugt werden soll.
// \return Nothing, but some global will be set. | Nichts, jedoch werden einige Globals erzeugt.
FUNCTION Init_FindPath: AFP_map[], x, y
GLOBAL AFP_mapmax_x=x
GLOBAL AFP_mapmax_y=y
LOCAL i%
DIM AFP_map[AFP_mapmax_x][AFP_mapmax_y] // Karte dimensionieren
// alle Felder der Karte auf 1 setzen, sie als passierbar machen
SETCURRENTDIR("..")
SETCURRENTDIR("..")
SETCURRENTDIR("Bismarck")
SETCURRENTDIR("Karte")
OPENFILE(1, "karte2.txt", 1)
READLINE 1, AFP_mapmax_y
READLINE 1, AFP_mapmax_y
FOR x=0 TO AFP_mapmax_x-1
FOR y=0 TO AFP_mapmax_y-1
READBYTE 1, i%
AFP_map[x][y]=-2*(i-0.5)
NEXT
NEXT
CLOSEFILE 1

// "Bewegungsrichtung" zur Erstellung weiterer Knoten
GLOBAL AFP_dirx%[], AFP_diry%[], AFP_dirz%[]
DIMDATA AFP_dirx[], 0, 1, 0, -1, 1, 1, -1, -1
DIMDATA AFP_diry[], -1, 0, 1, 0, -1, 1, 1, -1
DIM AFP_dirz[8]
FOR i=0 TO 7
AFP_dirz[i] = (AFP_dirx[i] AND AFP_diry[i])+1
NEXT

// map dient der Ermittlung der Entfernung des jeweils aktuellen Knotens zu Ziel, vorausberechnung erfolgt um Geschwindigkeit gut zu machen
GLOBAL AFP_heuristic%[]
DIM AFP_heuristic[AFP_mapmax_x][AFP_mapmax_y]
FOR y=0 TO AFP_mapmax_y-1
FOR x=0 TO AFP_mapmax_x-1
AFP_heuristic[x][y]=SQR(x*x+y*y)
NEXT
NEXT
ENDFUNCTION

//! This function search a path.
//? Diese Funktion sucht einen Weg.
// \param Look FINDPATH() for details about the parameters! | Details der Parameter können unter FINDPATH() nachgesehen werden.
// \param AFP_map[] - Map, where you search a path. | Karte, durch die ein Weg gefunden werden soll.
// \param heuristik - 0=sortest 1=cheapest Way. | 0=kürzester 1=günstigster Weg.
// \param startx,starty - Startpoint. | Startpunkt.
// \param endx,endy - Destination. | Zielpunkt.
// \return Path length, or 0 if no path was found. | Weglänge, oder 0 falls kein Weg gefunden wurde.
FUNCTION Advanced_FindPath: AFP_map[], loesung[], heuristik, startx%, starty%, endx%, endy%

REDIM loesung[0]

// Validität der Parameter prüfen
IF startx=endx AND starty=endy THEN RETURN 0
IF endx<0 OR endy<0 OR endx>AFP_mapmax_x-1 OR endy>AFP_mapmax_y-1 THEN RETURN 0
IF startx<0 OR starty<0 OR startx>AFP_mapmax_x-1 OR starty>AFP_mapmax_y-1 THEN RETURN 0
IF AFP_map[endx][endy]<=0 THEN RETURN 0
IF AFP_map[startx][starty]<=0 THEN RETURN 0
IF heuristik<0 OR heuristik>1 THEN heuristik=1

STATIC nodemap[] // dient primär der Kennzeichnung bereits besuchter Felder
REDIM nodemap[0]
REDIM nodemap[AFP_mapmax_x][AFP_mapmax_y][2]

STATIC path[] AS TNode // Zwischenspeicher des gefundenen Wegs
REDIM path[0]

// Variablen mit der Endung -s gehören zur Suche von Start, Variablen mit der Endung -g gehören zur Suche vom Ziel
STATIC x%, y%, finish%, cost%, delta%, nodezahls%, nodezahlg%
finish=0; nodezahls%=0; nodezahlg%=0


STATIC opens[] AS TNode // Openlists für noch zu untersuchende Knoten
REDIM opens[1]
STATIC openg[] AS TNode
REDIM openg[1]
STATIC topen AS TNode

STATIC nodes[] AS TNode // Closedlists für abschließend untersuchte Knoten
REDIM nodes[1]
STATIC nodeg[] AS TNode
REDIM nodeg[1]
STATIC tnode AS TNode

// Startpunktdaten einlesen
opens[0].x = startx
opens[0].y = starty
opens[0].cost = 0
opens[0].parent = -1
nodemap[startx][starty][0] = 1

// Zielpunktdaten einlesen
openg[0].x = endx
openg[0].y = endy
openg[0].cost = 0
openg[0].parent = -1
nodemap[endx][endy][0] = 2

REPEAT // Wegsuche beginnen

// Wegsuche ausgehend vom Startpunkt
x = 0; cost = 2147483647
FOREACH topen IN opens[] // Ermittlet günstigsten Open-Knoten
delta = AFP_heuristic[ABS(topen.x-endx)][ABS(topen.y-endy)]
IF topen.cost+delta<cost
cost = topen.cost+delta
y = x
ENDIF
INC x
NEXT
tnode = opens[y]
DIMPUSH nodes[], tnode // übernimmt den Knoten in die Closedlist und löscht ihn aus der Openlist
DIMDEL opens[], y
INC nodezahls

FOR i=0 TO 7 // Untersuchung der 8 benachbarten Knoten
x = tnode.x + AFP_dirx[i]
y = tnode.y + AFP_diry[i]
IF x>-1 AND y>-1 AND x<AFP_mapmax_x AND y<AFP_mapmax_y // Knoten liegt auf der Karte
    IF AFP_map[x][y]>0 AND AFP_map[x][tnode.y]>0 AND AFP_map[tnode.x][y]>0 // Knoten ist begehbar
IF nodemap[x][y][0]=0 // Knoten wurde noch nicht besucht
topen.x = x
topen.y = y
topen.parent = nodezahls
topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i]
DIMPUSH opens[], topen // erzeuge neuen Openknoten
nodemap[x][y][0]=1
nodemap[x][y][1]=nodezahls
ELSEIF nodemap[x][y][0]=2 // Knoten wurde bereits durch die andere Suchroutine erreicht -> Suche erfolgreich
topen.x = x
topen.y = y
topen.parent = nodezahls
topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i] + nodeg[nodemap[x][y][1]].cost
DIMPUSH path[], topen // erzeuge neuen Openknoten
finish = 1
ENDIF
ENDIF
ENDIF
NEXT

IF NOT LEN(opens[]) THEN finish=3 // Wenn kein Openknoten mehr existiert -> keine Verbindung zwischen Start und Ziel möglich -> Suche abbrechen

IF finish THEN BREAK

// Wegsuche ausgehend vom Zielpunkt
x = 0; cost = 2147483647
FOREACH topen IN openg[] // Ermittlet günstigsten Open-Knoten
delta = AFP_heuristic[ABS(topen.x-startx)][ABS(topen.y-starty)]
IF topen.cost+delta<cost
cost = topen.cost+delta
y = x
ENDIF
INC x
NEXT
tnode = openg[y]
DIMPUSH nodeg[], tnode // übernimmt den Knoten in die Closedlist und löscht ihn aus der Openlist
DIMDEL openg[], y
INC nodezahlg

FOR i=0 TO 7 // Untersuchung der 8 benachbarten Knoten
x = tnode.x + AFP_dirx[i]
y = tnode.y + AFP_diry[i]
IF x>-1 AND y>-1 AND x<AFP_mapmax_x AND y<AFP_mapmax_y // Knoten liegt auf der Karte
IF AFP_map[x][y]>0 AND AFP_map[x][tnode.y]>0 AND AFP_map[tnode.x][y]>0 // Knoten ist begehbar
IF nodemap[x][y][0]=0 // Knoten wurde noch nicht besucht
topen.x = x
topen.y = y
topen.parent = nodezahlg
topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i]
DIMPUSH openg[], topen // erzeuge neuen Openknoten
nodemap[x][y][0]=2
nodemap[x][y][1]=nodezahlg
ELSEIF nodemap[x][y][0]=1 // Knoten wurde bereits durch die andere Suchroutine erreicht -> Suche erfolgreich
topen.x = x
topen.y = y
topen.parent = nodemap[x][y][1]
topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i] + nodes[topen.parent].cost
DIMPUSH path[], topen // erzeuge neuen Openknoten
nodemap[x][y][0]=2
nodemap[x][y][1]=nodezahlg
finish = 1
ENDIF
ENDIF
ENDIF
NEXT

IF NOT LEN(openg[]) THEN finish=3 // Wenn kein Openknoten mehr existiert -> keine Verbindung zwischen Start und Ziel möglich -> Suche abbrechen

UNTIL finish // Wegsuche beendet

IF finish=3 THEN RETURN 0 // es wurde kein Weg gefunden

    x = 0; y=0; cost = 2147483647
FOREACH topen IN path[] // Ermittlet günstigsten Open-Knoten
IF topen.cost<cost
cost = topen.cost
y = x
ENDIF
INC x
NEXT
topen = path[y]
cost=topen.parent
delta=nodemap[topen.x][topen.y][1]
REDIM path[0]
DIMPUSH path[], topen

tnode = nodes[cost] // gefundenen Pfad vom Startpunkt aus auswerten
WHILE tnode.parent <> -1
DIMPUSH path[], tnode
tnode = nodes[tnode.parent]
WEND
DIMPUSH path[], tnode
REDIM nodes[0]

cost = LEN(path[])
REDIM loesung[cost][2]
FOR i=cost-1 TO 0 STEP -1
loesung[i][0] = path[cost-i-1].x
loesung[i][1] = path[cost-i-1].y
NEXT
REDIM path[0]

IF nodezahlg // gefundenen Pfad vom Zielpunkt aus auswerten
tnode = nodeg[delta]
WHILE tnode.parent <> -1
delta=tnode.parent
DIMPUSH path[], tnode
tnode = nodeg[tnode.parent]
WEND
DIMPUSH path[], tnode
REDIM nodeg[0]

delta = cost+LEN(path[])
REDIM loesung[delta][2]
FOR i=delta-1 TO cost STEP -1
loesung[i][0] = path[i-cost].x
loesung[i][1] = path[i-cost].y
NEXT
REDIM path[0]
ENDIF

RETURN delta

ENDFUNCTION

// Knoten, ein (möglicher) Schritt zum Ziel
TYPE TNode
cost% // bisherige Wegkosten
parent% // ID des Vorgängerknotens
x%
y%
ENDTYPE
#13
Hallo,

habe hier mal ein kleines Testprojekt um ein paar Probleme zu dokumentieren, auf die ich gestoßen bin. Das Bild zeigt was ich meine:

1. Die gesamte Szene ist zu dunkel. Der Untergrund bspw. ist eigentlich weiß! Wenn ich kein Licht erzeuge ist alles ok, d.h. hell, erzeuge ich aber ein Licht (z.B. um Schatten erzeugen zu können), ist es so dunkel wie im Bild. Vermutlich ist das kein Bug, sondern nur ein Fehler meinerseits? Bitte um Hilfe.
2. Der Schattenwurf ist vollkommen falsch, es wirkt als würde das Licht viel niedriger hängen, als es hängt. Mir ist aufgefallen, dass dies nur bei skaliertem Mesh auftritt, behalte ich die Ursprungsgröße bei, sind die Schatten korrekt.
3. Eine "Lücke" im Schatten. Ich habe keine Ahnung, wie das kommt, aber mir ist folgendes aufgefallen: importiere ich das Objekt aus .md2 oder .obj tritt diese Lücke (und andere Fehler) auf, importiere ich aus .3ds gibt es diese Lücke nicht. Möglicherweise ein Fehler im 3d-Converter?

Beispielprojekt ist angehangen.

Vielen Danke.

[attachment deleted by admin]