Sign in to follow this  

Problem saving/loading bytecodes (angelscript bug?)

This topic is 3811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there! I'm trying to save/load to/from bytecode file. But if i use arrays in the script, the application crashes with an access violation when loading the binary file:
// NEXT: Must go through the bytecode and set the correct objecttype pointer where used
int asCRestore::Restore() 
{
	// Before starting the load, make sure that 
	// any existing resources have been freed
	module->Reset();

	unsigned long i, count;

	asCScriptFunction* func;
	asCProperty* prop;
	asCString *cstr;

	// structTypes[]
	READ_NUM(count);
	module->classTypes.Allocate(count, 0);
	for( i = 0; i < count; ++i )
	{
		asCObjectType *ot = NEW(asCObjectType)(engine);
		ReadObjectTypeDeclaration(ot);
		engine->classTypes.PushLast(ot);
		module->classTypes.PushLast(ot);
		ot->refCount++;
	}

	// usedTypes[]
	READ_NUM(count);
	module->usedTypes.Allocate(count, 0);
	for( i = 0; i < count; ++i )
	{
		asCObjectType *ot = ReadObjectType();
		module->usedTypes.PushLast(ot);
		ot->refCount++;		
	}
.
.
.
}
In the last line (ot->refCount++) ot is NULL, so there i have the access violation. Here's the script i've used:
Sprite		spr;
float[]		f(5);

bool Initialize() {
	if (!spr.Load("data/graphics/roxy.spr"))
		return false;

	spr.SetFrame(10);
	spr.SetPos(20,20);

	return true;
}

void Update(float dt) {
	spr.Update(dt);
}

void Draw() {
	spr.Draw();
}
If I comment the float[] f(5); line, the problem dissapear. Is it something i'm doing wrong when registering the arrays? Here is how I registered the floats array:
	if (ScriptMgr::RegisterObjectType("float[]", sizeof(vector<float>), asOBJ_CLASS_CDA) < 0)
		return false;
	if (ScriptMgr::RegisterObjectBehaviour("float[]", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(ConstructFloatArray, (vector<float> *), void), asCALL_CDECL_OBJLAST) < 0)
		return false;
	if (ScriptMgr::RegisterObjectBehaviour("float[]", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTIONPR(ConstructFloatArray, (int, vector<float> *), void), asCALL_CDECL_OBJLAST) < 0)
		return false;
	if (ScriptMgr::RegisterObjectBehaviour("float[]", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructFloatArray), asCALL_CDECL_OBJLAST) < 0)
		return false;
	if (ScriptMgr::RegisterObjectBehaviour("float[]", asBEHAVE_ASSIGNMENT, "float[] &f(float[]&in)", asMETHODPR(vector<float>, operator=, (const std::vector<float> &), vector<float>&), asCALL_THISCALL) < 0)
		return false;
	if (ScriptMgr::RegisterObjectBehaviour("float[]", asBEHAVE_INDEX, "float &f(int)", asMETHODPR(vector<float>, operator[], (vector<float>::size_type), float &), asCALL_THISCALL) < 0)
		return false;
	if (ScriptMgr::RegisterObjectMethod("float[]", "int length()", asMETHOD(vector<float>, size), asCALL_THISCALL) < 0)
		return false;
Thanks a lot!

Share this post


Link to post
Share on other sites
I haven't done any extensive testing on the save/load feature, so it's entirely possible that it is a bug in AngelScript itself. I'll have to make some tests with your example to see what I can find.

Regards,
Andreas

Share this post


Link to post
Share on other sites
oh! Okey, it was driving me crazy!!

Well, I'll wait anxious to the next release! ;)

Thanks a lot for the answer and for the fantastic angelscript that i'm using in my games engine!


Share this post


Link to post
Share on other sites
I'm still having problems when saving/loading bytecode. It works well but when i try to resize a script array, it crash with an unhandled exception. Here is the angelscript code i'm using:

const int COLLISION_MAX_ENTITIES = 200;

class CheckCollision {

Actor@[] _list1;
Actor@[] _list2;

int _lastList1;
int _lastList2;

bool Initialize() {
_list1.resize(COLLISION_MAX_ENTITIES);
_list2.resize(COLLISION_MAX_ENTITIES);
_lastList1 = 0;
_lastList2 = 0;
return true;
}
.
.
.
}


The problem resides in the resizes. When I try to resize the arrays, it crashes with an unhandled exception in as_arrayobject.cpp method:


static void ArrayObjectResize(asUINT size, asCArrayObject *self)
{
self->Resize(size);
}


If I try the same code without the preloaded bytecode, it works well.

Thanks!!!!

Share this post


Link to post
Share on other sites
I'm unable to reproduce this last problem. I wrote the following test case:


static const char *script4 = " \n"
"const int COLLISION_MAX_ENTITIES = 200; \n"
"interface Actor { void Test(); } \n"
"class CheckCollision { \n"
" Actor@[] _list1; \n"
" Actor@[] _list2; \n"
" int _lastList1; \n"
" int _lastList2; \n"
" \n"
" bool Initialize() { \n"
" _list1.resize(COLLISION_MAX_ENTITIES); \n"
" _list2.resize(COLLISION_MAX_ENTITIES); \n"
" _lastList1 = 0; \n"
" _lastList2 = 0; \n"
" return true; \n"
" } \n"
"}";


bool Test()
{
int r;

// Compile and save the byte code
asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->AddScriptSection(0, "script", script4, strlen(script4));
r = engine->Build(0);
if( r < 0 ) fail = true;
CBytecodeStream stream4;
engine->SaveByteCode(0, &stream4);
engine->Release();

// Load and execute the byte code
engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->LoadByteCode(0, &stream4);
r = engine->ExecuteString(0, "CheckCollision c; c.Initialize();");
if( r != asEXECUTION_FINISHED )
fail = true;
engine->Release();

return fail;
}






The test passed without any problems.

Would you mind giving the above test a try on your target system to see if it reproduces your problem? I'll need your help to fix the problem. Without being able to reproduce the problem myself it can be next to impossible to fix.

Regards,
Andreas

Share this post


Link to post
Share on other sites
I've ran your test and it works well...

I couldn't figure out what's going on with my code and I don't know how to show you without sending all of it (because it's big to be pasted in the forum).

What else could I try?


Share this post


Link to post
Share on other sites
You say the code crashes inside the array resize. Do you know if the resize is called from Initialize() or maybe it is called at another moment when there are already some elements in it? In other word does your problem only happen inside CheckCollision.Initialize() or in other locations of your scripts as well? Does it always happen at the same moment, or is it only sometimes?

Would it be possible to try to narrow down the location of the problem by commenting out half of your script, then test again? Continue with that recursively until you've identified the problematic components.

Share this post


Link to post
Share on other sites
It happens always. If I comment the resize lines in initialize, i have another crash in:

int asSGCObject::AddRef()
{
// TODO: Must be made atomic
// Increase counter and clear flag set by GC
refCount = (refCount & 0x7FFFFFFF) + 1;
return refCount;
}



The line that through the error is:

if (!_ship.Initialize())
return false;



But it crashes before executing any line in the Initialize method. Here is the declarations:


#include "constants.as"
#include "globals.as"
#include "ship.as"

const int GAME_STATE_NONE = 0;
const int GAME_STATE_EXIT = 1;
const int GAME_STATE_NEXTLEVEL = 2;

class InGame {
Ship _ship;
int _state;

bool Initialize(int level) {
_state = GAME_STATE_NONE;

_asteroidsCount = 0;

Log("Initialize InGame CheckCollision...");
if (!g_checkCollision.Initialize())
return false;

Log("Initialize InGame Ship...");
if (!_ship.Initialize())
return false;

if (!g_AsteroidMgr.Initialize(level))
return false;

return true;
}
.
.
.
}

const int SHOTS_COUNT = 10;

const float SHIP_ANIM_FPS = 15.0f;
const float SHIP_ROT_SPEED = 0.2f;
const float SHIP_MAXSPEED = 0.4f;
const float SHIP_ACCEL = 0.0003f;

const int SHIP_STATE_NONE = 0;
const int SHIP_STATE_INVISIBLE = 1;
const int SHIP_STATE_EXPLODING = 2;

const float INVISIBLE_TIME = 2000.0f;

class Ship : Actor {
float _accumTime;
float _angle;
float _vx;
float _vy;

int _lastShot;
int _lives;

int _state;

float _invisibleTime;

uint _currentColor;

Sprite _sprite;
Sprite _sprExplosion;
Animation _aniExplosion;
Shot@[] _shots;

string GetName() {
return _sprite.GetName();
}

float GetPosX() { return _sprite.GetPosX(); }
float GetPosY() { return _sprite.GetPosY(); }
float GetCollisionRadius() { return _sprite.GetCollisionRadius(); }
bool GetCheckCollision() { return _sprite.GetCheckCollision(); }

bool Initialize() {
Log("Initialize");
if (!_sprite.Load("data/graphics/uridium.spr")) {
return false;
}

if (!_sprExplosion.Load("data/graphics/explosion.spr"))
return false;

if (!_aniExplosion.Load("data/graphics/explosionNave.ani"))
return false;

Log("Shots resize");
_shots.resize(SHOTS_COUNT);

Log("Shots intialize");
for (int i=0; i < SHOTS_COUNT; i++) {
Shot shot;

@_shots[i] = @shot;

if (!_shots[i].Initialize())
return false;
}

Reset();
.
.
.
.
}



I don't know what's going on here. :(

Share this post


Link to post
Share on other sites
Witchlord, you should run that test as two separate apps. It's possible for some error to slip through because some improperly loaded bit of code refers to deleted memory that just happens to still hold correct data.

Share this post


Link to post
Share on other sites
You may be right, Deyja. I'll give that a try.

I'm however more inclined to think it has something to do with object type conflicts inside the engine, maybe a combination of script classes and registered classes. In my small test the conflict doesn't appear, but with the larger script from mckracken there may be problems while registering the objects.

Share this post


Link to post
Share on other sites
By adding more complexity to the script I was able to reproduce the problem.

It happens with the following script:


interface Actor { }
InGame g_inGame;
class InGame
{
Ship _ship;
bool Initialize(int level)
{
if (!_ship.Initialize())
return false;

return true;
}
}
class Ship : Actor
{
bool Initialize()
{
return true;
}
}






and engine->ExecuteString(0, "g_inGame.Initialize(0);")

If I remove the Actor interface the problem doesn't happen anymore. Which may be a good lead to the cause of the problem.

Now that I've reproduced it, it shouldn't be long before I have it fixed. Hopefully it is the last of the bugs that have been bothering.

While trying to reproduce your problem I also stumbled upon another bug that I need to fix. This one is an assert failure in the script compiler after trying to recover from a compile errors. It shouldn't be too difficult to fix either.

I'll let you know as I have more information.

Regards,
Andreas

[Edited by - WitchLord on June 21, 2007 4:22:40 PM]

Share this post


Link to post
Share on other sites
I've discovered the problem. There is a design problem with the asCRestore class. It is currently not able to load script class declarations that are out of order. In the test the structure declarations are stored in the order: Actor, InGame, Ship, which is alright. But when the file is loaded again, the InGame structure is referencing a type that has not yet been registered in the engine (Ship). Because of that the _ship property is not properly initialized (the object type is set to null).

A work around for this problem is to make sure the script classes are declared in the right order. In the test the Ship class declaration must be moved up above the InGame class. Of course, if you have circular referencing of types, then there really is no work around.

I'll have this problem fixed as soon as possible.

Regards,
Andreas

Share this post


Link to post
Share on other sites
I've fixed the problem now. You can get the solution from the SVN (rev 159).

Let me know if there are more problems with the bytecode serialization. There likely is as my unit tests for this part are really weak and uncomplete so far, but hopefully everything that you need should work perfectly.

Regards,
Andreas

Share this post


Link to post
Share on other sites
It solved the problem but i have another yet. Now it brings me an error in:

int asSGCObject::Release()
{
// TODO: Must be made atomic
// Decrease counter and clear flag set by GC
refCount = (refCount & 0x7FFFFFFF) - 1;
if( refCount == 0 )
{
CONV2GCCLASS(this)->Destruct();
return 0;
}
return refCount;
}




in line "refCount = (refCount & 0x7FFFFFFF) - 1;" when I try this:


_shots.resize(SHOTS_COUNT);

for (int i=0; i < SHOTS_COUNT; i++) {
Shot shot;

@_shots[i] = @shot;

if (!_shots[i].Initialize())
return false;
}




If you need more info, let me know.

[EDIT]
I forgot to mention that the error occurs in "Shot shot;" line.
[/EDIT]

Share this post


Link to post
Share on other sites
You must be the first to truly use this save/load feature to its fullest. I can't believe this many problems would have gone unnoticed unless it was a feature that was never really used.

Unfortunately it is a feature where it is very difficult to predict the tests that are necessary to do a thurough code coverage, so it is bound to have more problems. But, if you'll be patient with me I promise I'll fix every last one of them as they are discovered.

Thanks for keeping the reports coming in.

Regards,
Andreas

Share this post


Link to post
Share on other sites
Hmm, just adding those lines to the example that reproduced the previous problem didn't reproduce the new problem. I'll try adding the rest of your example, to see if that may reproduce this new problem.

In the meantime: Is Shot an Actor as well? Or is it an application registered class?





Share this post


Link to post
Share on other sites
Please let me know how you've registered the classes involved, i.e. Sprite, Animation, g_checkCollision, g_AsteroidMgr.

I've not been able to reproduce the problem yet, even though I've added practically all of your shown script code. Maybe it has something to do with those other classes.

Share this post


Link to post
Share on other sites
The Sprite and Animation are C++ classes registered in the engine. The Sprite class in particular inherits from Shape that inherits from Entity2D and so on. I register them like this:


bool Shape::RegisterShape(char *className) {
char _className[100];

if (className != NULL) {
strcpy_s(_className, 100, className);
} else {
strcpy_s(_className, 100, "Shape");
if (ScriptMgr::RegisterObjectType(_className, sizeof(Shape), asOBJ_CLASS | asOBJ_CLASS_CONSTRUCTOR) < 0)
return false;

if (ScriptMgr::RegisterObjectBehaviour(_className, asBEHAVE_CONSTRUCT,"void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST) < 0)
return false;
if (ScriptMgr::RegisterObjectBehaviour(_className, asBEHAVE_DESTRUCT,"void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST) < 0)
return false;

if (ScriptMgr::RegisterObjectMethod(_className, "void Draw()", asMETHODPR(Shape, Draw, (void), void), asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void Update(float)", asMETHODPR(Shape, Update, (float), void), asCALL_THISCALL) < 0)
return false;

//-----------------------------------------
// Arreglos de Shapes
//-----------------------------------------
// Register std::vector<int>
if (!RegisterVector<Shape>("Shape[]", "Shape", (asIScriptEngine *)ScriptMgr::GetEngine()))
return false;
}

if (!Entity2D::RegisterEntity2D(_className))
return false;

if (ScriptMgr::RegisterObjectMethod(_className, "void SetShape(int)", asMETHODPR(Shape, SetShape, (int), void), asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetColor(uint)",asMETHOD(Shape, SetColor),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetColorPerVertex(uint,uint,uint)",asMETHODPR(Shape, SetColorPerVertex, (DWORD,DWORD,DWORD), void),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetColorPerVertex(uint,uint,uint,uint)",asMETHODPR(Shape, SetColorPerVertex, (DWORD,DWORD,DWORD,DWORD), void),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetRadius(float)",asMETHOD(Shape, SetRadius),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetSegmentsCount(int)",asMETHOD(Shape, SetSegmentsCount),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "bool IsColliding(Shape &in)",asMETHOD(Entity2D, IsColliding),asCALL_THISCALL) < 0)
return false;

return true;
}

bool Sprite::RegisterSprite(char *className) {
char _className[100];

if (className != NULL) {
strcpy_s(_className, 100, className);
} else {
strcpy_s(_className, 100, "Sprite");
if (ScriptMgr::RegisterObjectType(_className, sizeof(Sprite), asOBJ_CLASS | asOBJ_CLASS_CONSTRUCTOR) < 0)
return false;

if (ScriptMgr::RegisterObjectBehaviour(_className, asBEHAVE_CONSTRUCT,"void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST) < 0)
return false;
if (ScriptMgr::RegisterObjectBehaviour(_className, asBEHAVE_DESTRUCT,"void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void Draw()", asMETHODPR(Sprite, Draw, (void), void), asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void Update(float)", asMETHODPR(Sprite, Update, (float), void), asCALL_THISCALL) < 0)
return false;

//-----------------------------------------
// Arreglos de Sprites
//-----------------------------------------
// Register std::vector<int>
if (!RegisterVector<Sprite>("Sprite[]", "Sprite", (asIScriptEngine *)ScriptMgr::GetEngine()))
return false;

}

if (!Shape::RegisterShape(_className))
return false;

if (ScriptMgr::RegisterObjectMethod(_className, "Animation@ GetAnimation()",asMETHOD(Sprite, GetAnimation),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetAnimation(Animation &in)",asMETHODPR(Sprite, SetAnimation, (Animation*), void),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "void SetFrame(int)",asMETHOD(Sprite, SetFrame),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "int GetCurrentFrame()",asMETHOD(Sprite, GetCurrentFrame),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "bool IsAnimationRunning()",asMETHOD(Sprite, IsAnimationRunning),asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "bool Load(string &in)", asMETHODPR(Sprite, Load, (const string&), bool), asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "bool Unload()", asMETHOD(Sprite, Unload), asCALL_THISCALL) < 0)
return false;
if (ScriptMgr::RegisterObjectMethod(_className, "bool IsColliding(Sprite&in)",asMETHOD(Entity2D, IsColliding),asCALL_THISCALL) < 0)
return false;


return true;




And so on. So you register the methods once per class just by calling the register method.

The others (g_checkCollision and g_asteroidMgr) are instances from script declared classes.


class CheckCollision {

Actor@[] _list1;
Actor@[] _list2;

int _lastList1;
int _lastList2;

bool Initialize() {
_list1.resize(COLLISION_MAX_ENTITIES);
_list2.resize(COLLISION_MAX_ENTITIES);
_lastList1 = 0;
_lastList2 = 0;
return true;
}

bool Register(Actor@ entity, int list){
switch (list) {
case 1:
if (_lastList1 < COLLISION_MAX_ENTITIES) {
@_list1[_lastList1] = @entity;
_lastList1++;
return true;
}
break;
case 2:
if (_lastList2 < COLLISION_MAX_ENTITIES) {
@_list2[_lastList2] = @entity;
_lastList2++;
return true;
}
break;
}

return false;
}

bool Unregister(Actor@ entity, int list) {
int i=0;

switch (list) {
case 1:
while (i<_lastList1 && @_list1[i] != @entity)
i++;

if (@_list1[i] == @entity) {
_lastList1--;
@_list1[i] = @_list1[_lastList1];
return true;
}
break;
case 2:
while (i<_lastList2 && @_list2[i] != @entity)
i++;

if (@_list2[i] == @entity) {
_lastList2--;
@_list2[i] = @_list2[_lastList2];
return true;
}
break;
}
return false;
}

void Clear() {
_lastList1 = 0;
_lastList2 = 0;
//_list1.resize(0);
//_list2.resize(0);
}

void Check() {
float x1;
float y1;
float r1;
float x2;
float y2;
float r2;

for (int i=0; i < _lastList1; i++) {
x1 = _list1[i].GetPosX();
y1 = _list1[i].GetPosY();
r1 = _list1[i].GetCollisionRadius();

for (int j=0; j < _lastList2; j++) {
x2 = _list2[j].GetPosX();
y2 = _list2[j].GetPosY();
r2 = _list2[j].GetCollisionRadius();
if (_list1[i].GetCheckCollision() && _list2[j].GetCheckCollision()) {
if ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) <= (r1+r2)*(r1+r2)) {
_list1[i].OnCollide(_list2[j]);
_list2[j].OnCollide(_list1[i]);
}
}
}
}
}


}

class AsteroidMgr {

Asteroid[] _asteroids;

void Clear() {
for (int i=0; i < _asteroids.length(); i++) {
_asteroids[i].Shutdown();
}
//_asteroids.resize(0);
}

bool Initialize(int asteroidCount) {
if (asteroidCount <= 0)
return false;

_asteroids.resize(asteroidCount);

for (int i=0; i < _asteroids.length(); i++) {
if (!_asteroids[i].Initialize())
return false;

_asteroids[i]._sprite.SetVisible(true);
_asteroids[i]._sprite.SetCheckCollision(true);
}

return true;
}

void Update(float dt) {
for (int i=0; i < _asteroids.length(); i++) {
_asteroids[i].Update(dt);
}
}

void Draw() {
for (int i=0; i < _asteroids.length(); i++) {
_asteroids[i].Draw();
}
}

void Shutdown() {
for (int i=0; i < _asteroids.length(); i++) {
_asteroids[i].Shutdown();
}
//_asteroids.resize(0);
}

}

AsteroidMgr g_AsteroidMgr;
CheckCollision g_checkCollision;




Here is the Shot class:


const float SHOT_SPEED = 0.6f;

class Shot : Actor {
Sprite _sprite;

float _vx;
float _vy;

float GetPosX() { return _sprite.GetPosX(); }
float GetPosY() { return _sprite.GetPosY(); }
float GetCollisionRadius() { return _sprite.GetCollisionRadius(); }
bool GetCheckCollision() { return _sprite.GetCheckCollision(); }

void SetVisible(bool visible) {
_sprite.SetVisible(visible);
}

bool GetVisible() {
return _sprite.GetVisible();
}

string GetName() {
return _sprite.GetName();
}

bool Initialize() {
if (!_sprite.Load("data/graphics/shot.spr"))
return false;

_vx = 0;
_vy = 0;

_sprite.SetVisible(false);

_sprite.SetName("shot");
_sprite.SetCheckCollision(false);
_sprite.SetCollisionRadius(5);

if (!g_checkCollision.Register(this, 1))
return false;

return true;

}

void Shoot(float fromX, float fromY, float angle) {
_sprite.SetPos(fromX, fromY);
_sprite.SetAngleZ(angle);

_vx = SHOT_SPEED*cos(angle);
_vy = SHOT_SPEED*sin(angle);

_sprite.SetVisible(true);
_sprite.SetCheckCollision(true);
}

void Update(float dt) {
_sprite.Update(dt);

float x = _sprite.GetPosX();
float y = _sprite.GetPosY();
int w = g_graphics.GetViewportWidth()/2;
int h = g_graphics.GetViewportHeight()/2;

x += _vx * dt;
y += _vy * dt;

// Verificamos si la posición
// atraviesa alguno de los extremos
// de la pantalla
if (abs(x) > w || abs(y) > h) {
_sprite.SetVisible(false);
_sprite.SetCheckCollision(false);
}

_sprite.SetPos(x, y);
}

void Draw() {
_sprite.Draw();
}

void Shutdown() {
_sprite.Unload();
}

void OnCollide(Actor@+ actor) {
_sprite.SetVisible(false);
_sprite.SetCheckCollision(false);
}

}




[edit]
I've made a mistake before, the problem is in the line:

@_shots[i] = @shot;


[/edit]

Share this post


Link to post
Share on other sites

This topic is 3811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this