Unable to assign a dinamic sprite to object.Graphic

Started by JpSoft, Tue 27/05/2008 11:34:17

Previous topic - Next topic

JpSoft

Im creating a module to give a 3D aspect to the scenarios.Its my first module so im sorry if it is not very well explained. Basically, the room need 2 backgrounds, where the 2nd is static (to read the background) and the first one is where the drawing functions works. Its designed for a 640x400 game only, but it could be adjusted with MaxX and MaxY variables.

Code: ags

// MODULO Perspectiva

int MaxX = 320;
int MaxY = 200;
int VarianteX, LineaADibujar, Ancho, StartX;
bool EnPantallaX, EnPantallaY, Mostrar;
float zoom,  aux;
int zoomint, altura, newwidth, newheight;

function Perspectiva()  // Give a deep aspect to the scenario

{
DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
LineaADibujar = 0;
while (LineaADibujar < 200)
  {
  VarianteX = -40+(LineaADibujar*2/5); // Between -40 y 40
  StartX = GetViewportX()+(VarianteX);
  if (StartX < 0) StartX = 0;
  Ancho = 400-(LineaADibujar*4/5); // Between 400 y 240
  if (StartX+400 > 959) StartX = 959-400;
  DynamicSprite* sprite = DynamicSprite.CreateFromBackground(1, StartX, GetViewportY()+LineaADibujar, Ancho,1);
  surface.DrawImage(GetViewportX(),GetViewportY()+ LineaADibujar, sprite.Graphic, 0, 320, 1);
  sprite.Delete();
  LineaADibujar++;
  }

altura = object[0].Y-GetViewportY(); // Distance to the top
if (altura <= 0) zoom=0.8; // If up of the screen, draw it small
if (altura > 0)
  {
  zoom = 0.8+(IntToFloat(altura)*0.0076);
  if (zoom > 2.5) zoom = 2.5;
  }
zoomint = FloatToInt(zoom, eRoundNearest);

if ((object[0].X > GetViewportX()) && (object[0].X < GetViewportX()+319)) EnPantallaX = true;
else EnPantallaX = false;
if ((object[0].Y > GetViewportY()) && (object[0].Y < GetViewportY()+199)) EnPantallaY = true;
else EnPantallaY = false;
if ((EnPantallaX == true) && (EnPantallaY == true)) Mostrar = true;
else Mostrar = false;
if (Mostrar == true)
  {
  cCharacter.SayBackground ("Object on Screen");
  DynamicSprite* sprite = DynamicSprite.CreateFromExistingSprite(object[0].Graphic);
  newwidth = FloatToInt(IntToFloat(sprite.Width)*zoom, eRoundNearest);
  newheight = FloatToInt(IntToFloat(sprite.Height)*zoom, eRoundNearest);
  sprite.Resize(newwidth,newheight);
  surface.DrawImage(object[0].X, object[0].Y-newheight, sprite.Graphic);
  // Why object[0].Graphic = sprite.Graphic doesnt works??
    
  }
else cCharacter.SayBackground ("Not now");

surface.Release();
}


The trouble is near to the bottom: when i try to assign the resized image to the object[0] (its only for test, later i can add a loop from 0 to object_count) suddenly the object dissapears from the screen. Anyone can help me with this? The X position is not yet adjusted, but it can be easily dome (hopefully)

Here is a link with the source code im working for testing purposes.

http://rapidshare.com/files/117975563/FWars.rar

Wich also have the easy3D module 1.0.4 updated to AGS 3.0

Thanks

Jp



GarageGothic

#1
Declare the DynamicSprite at the top of the script, outside the function like so:

Code: ags
DynamicSprite* sprite;


And inside the function, just put:

Code: ags
sprite = DynamicSprite.CreateFromExistingSprite(object[0].Graphic);


Otherwise the DynamicSprite pointer will be deleted when the function finishes, and yes, your object will disappear (or in some cases become the default bluecup).

Edit: Also, if you haven't done so already, you may want to upgrade to AGS 3.0.2 when the final version comes out. With the new DynamicSprite.CreateFromDrawingSurface function, it shouldn't really be necessary to have two backgrounds, just make a temporary copy of the background in the EnterRoomBeforeFadein event.

JpSoft

What a fast and usefull answer! I already tested it and it works, the object keep the new graphic assigned.
But now, next time the object must be updated, the sprite will be bigger or smaller from the original one and zoom functions will not work properly. Any idea how i could store the default images to check it when i need them?

(im becoming to feel a headache when i try to imagine how i can make this module work with animated objects  ???)

Thanks a lot

Jp

GarageGothic

#3
First of all, check my edit to my previous post if you haven't already. It's not related to your question but could save you some trouble.

Second, please explain exactly what it is you're trying to do. My impression was that you get sprites from objects, scale them and then draw them to the background. Do you also need to assign the scaled sprites back to the object? I thought that was for debug purposes only?
It shouldn't be difficult to store the original sprite number for each object in an array, so it's not a problem to restore them to original size. I just wonder if it's necessary to change their graphics in the first place.

Anyway, to answer your question, you could create a dynamic array to store the original sprite numbers. Like so:

Outside the function define:

Code: ags
int origsprite[];


Then define it's size in EnterScreenBeforeFadeIn:

Code: ags
function on_event (EventType event, int data) {
   if (event = eEventEnterRoomBeforeFadein) {
      origsprite = new int[Room.ObjectCount]
      }
   }


Then, inside your function, before changing the sprite, you store the original sprite value for the item you change:

Code: ags
int objectnum = 2; //just an example, you'd probably use a while loop to run through all the objects
if (origsprite[objectnum] == 0) origsprite[objectnum] = object[objectnum].Graphic; // I added the conditional so it would only store it the first time around


This is a bit of a mess with animated sprites though, which is also one of the reasons I'd like you to explain the functionality of the module in a bit more detail. Perhaps there are easier ways.

JpSoft

Well, the idea of the module is to give a around 50 degrees perspective  from the backfround (which is actually a big scrolling room). It could be easily explained if you download the source code and run the game. The objects need be scaled acording to their position in the screen (if they are in the screen, of course): bigger when they are closer to the bottom of the screen and smaller when you scroll down.

The idea of this module is play a RTS game in 3D scenarios despite just plain 2D scenarios. The first part of the module works great (for the room ground) but of course, the hardest part is objects and characters. I tried with the Eady3D module, but it dosnt works for me.

Thanks for your help,

Jp


GarageGothic

#5
Ah yes, I see the point now. It's a pretty neat effect you've come up with.

The array I described earlier should work for static objects. However, for animating objects and characters it's a bit more difficult. You could write your own animation code handled through repeatedly_execute_always (with a struct storing the view, loop, current frame and animation speed as well as a timer to let us know when to change the frame), but that's quite a big job. Another way would be to hide all characters and objects and use DrawImage to replicate them on-screen. This approach will cause problems with pathfinding though, if you need to use that.
The easy workaround of replicating all objects and characters in the room using a bunch of dummy characters could work if it's only to be used in your own game. But if you plan to distribute the module it's not an optimal solution.

JpSoft

Draw directly the objects (and chars) into the BGs do not works since the player needs interact with them at any moment. I feel i can now create the module to work perfect with static objects, but of course, to keep the animation while its re-scaled and repositioned looks to be a very hard thing to do (maybe some of the monsters-scripters could do that in some hours, but it could take me weeks)

I will finish the perspective module without animations. If anyone have a good idea to be able and keep the animations just let me know.

Jp

PS If someone wants to help in the project with the creation of this module would be very helpful

GarageGothic

#7
Ah great, the forum is back up. I originally tried to post this many hours ago:

The interaction part can always be handled in a custom click function by storing the coordinates and current size of the object in a struct. Just check for clicks on objects in the module's on_mouse_click code and then run the relevant Object.RunInteraction(CursorMode) from there. You can even do pixel perfect click detection by using a modified this technique, which I came up with as a workaround for pixel perfect GUI buttons (only requires a single dummy character).

The main issue is the pathfinding, as I said. It can be handled by using WalkStraight and then checking for objects a certain number of pixels ahead of the character in his walking direction. But of course it will never be quite as "intelligent" as the built-in pathfinder. It's definitely possible but will take a bit of planning not to cause AI characters to get stuck.

Good luck with the project. Unfortunately I don't have the time to join your efforts, but it's quite an interesting challenge you've set yourself, and I'd be happy to try to help out with any further questions you might have.

Edit: All this would be a piece of cake if only there was an Object.Scaling property. Perhaps the best idea would just be to let CJ know that such a feature would be put to good use. I already suggested it in the AGS 3.02 Wishlist some days ago.

Edit 2: I didn't consider this at all, since the original question was about DynamicSprites. But have you experimented with the SetAreaScaling function? If the object scaling is fairly linear, at least within the same screen area, you should be able to make a full-screen walkable area and change it's scaling depending on the viewport coordinates (so that the bottom of the screen always is 100%). Might take some tweaking to fit into your other perspective effect though, and because the scrolling room is so big, it may be necessary to split the walkable area into several horizontal slices - otherwise you would only be able to scale all the way up to 100% in the bottom half of the room.

JpSoft

Yes, a object.setscale property could be very usefull, but its really not the big problem for this module. The scaling formula is easy to calculate and i only need add transparent borders  to the object original image (at both sides); so, when the object become fair, its just need reduce the empty space around the object (i hope i was enough clear). BTW its not necessary change the object coordinates  :D At least, in my game proyect, objects do not need find paths since they are static, and chars can be handly re-escaled. Im sure i will be able to make this module at least for static objects (i prefer have static objects in the game but with the 3D perspective)

My first try for this module was using the technique of divide the room in many horizonatal walkable areas, but it looks odd. Since you cant have more than 15 walkable areas in the screen at the same moment (to avoid a wrong result) the perspective was bad and the parallax effect did not work properly. That was the reason i coded it reading any line from the BG. (you can check that only the area you are looking is re-scaled  to avoid a low performance)

Thanks for your feedback. Im very excited about this idea to include in my game and i hope it will become to true. Of course, any new doubt i could have for the scripting, you all will know that  ;)ç

Thanks a lot

Jp


GarageGothic

Yeah, with non-animating objects everything should work fine. In case you need something to animate you could always fake it with a character. It's quite clever to add transparent borders instead of simply resizing, I didn't think of that workaround to keeping the sprites centered on the same coordinate. Good idea.

I look forward to see what comes out of this project.

SMF spam blocked by CleanTalk