Hello,
I'm just trying out multiple ways to do the same thing...at first this seemed unbelievable simple should it work, my original idea was this (this you will understand ... better) :
I'm moving my character on the onMOVE with vx, vy (velocity), then testing for Collision, if my character collides with TPlatForm... then I check if he was going up down left or right... and according to that I set my character position to be positioned next to wall , like this :
if my character is going up, and he hits the TPlatform right above I do the following , Y:=TPlatForm(Sprite).Y+TPlatForm(Sprite).Height; set my character's Y coordinate to
TPlatForm(Sprite) -> this is the Sprite I've hit Y+ it's Height, so I'm right bellow it, no empty space... no need to check speed or whatever since it's not possible to get inside it this way.
Anyway when I've tried this out I was amazed that it worked, and that it's such a simple solution ... the problem came when I was trying to do the following :
Pressed up to hit the wall... then I've kept pressing up... and then tried to move left and right along the upper part... my character was moving incorrectly (at very high speed)... so I've tried the following to make it good, if I hit upper or lover sprite I've set vx:=0, if I've hit left or right I've set vy:=0, now this fixed my problem or so I thought... when I've hit the sprite above me or bellow and kept pressing up or down and at the same time left and right I was moving along the wall nicely... but if there was some obstacle next to me and I've reached it... my character "magicaly" transported itself right in top of it or bellow, since the code was always placing my character just bellow or above a sprite should it collide.
error.jpg
In this case I was pressing up Constantly and right as well, I was moving fine allong the wall , until I've reached the corner... there what happened was my Characters Y position was updated to the Y position of the sprite I've hit from RIGHT side.
Code:
unit Main;
interface
uses
Windows,Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, AdDraws, AdClasses, AdTypes, AdPerformanceCounter, AdDevIL,AdSprites,Math;
const
TileW = 32; // tile width
TileH = 32; // tile height
PlayerH = 60; // Player Height
PlayerW = 30; // Player Width
type
TPlatform = class(TImageSprite)
private
protected
procedure DoMove(TimeGap: Double); override;
procedure DoCollision(Sprite:TSprite; var Done:boolean); override;
public
constructor Create(AParent:TSprite);override;
end;
TBlurp = class(TImageSprite)
private
vx,vy : Single; //current velocity in pixels/second
protected
procedure DoMove(TimeGap: Double);override;
procedure DoCollision(Sprite:TSprite; var Done:boolean);override;
public
constructor Create(AParent:Tsprite);override;
end;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
AdDraw:TAdDraw;
AdSpriteEngine:TSpriteEngine;
AdImageList:TAdImageList;
AdPerCounter:TAdPerformanceCounter;
AdPixelCollisionTester: TAdSpritePixelCollisionTester;
Blurp:TBlurp;
procedure Idle(Sender:TObject; var Done:boolean);
procedure LoadLevel;
end;
var
Form1: TForm1;
ActTime : double;
// camera positions
camera_x : double;
camera_y : double;
implementation
{$R *.dfm}
procedure TForm1.LoadLevel;
var
level:TStringList;
ax,ay:integer;
begin
level := TStringList.Create;
level.LoadFromFile(ExtractFilePath(Application.ExeName)+'level2.txt');
for ay := 0 to level.Count-1 do
begin
for ax := 1 to length(level[ay]) do
begin
case level[ay][ax] of
'x':
begin
with TPlatform.Create(AdSpriteEngine) do
begin
Image := AdImageList.Find('WALL');
x := ax*TileW;
y := ay*TileH;
z := 0;
end;
end;
'X':
begin
with TPlatForm.Create(AdSpriteEngine) do
begin
Image := AdImageList.Find('WALL');
x := ax*TileW;
y := ay*TileH;
z := 0;
end;
end;
end;
end;
end;
level.Free;
end;
constructor TPlatform.Create(AParent: TSprite);
begin
inherited;
end;
constructor TBlurp.Create(AParent: TSprite);
begin
inherited;
end;
procedure TBlurp.DoMove(TimeGap: Double);
begin
inherited;
// setting the camera to follow our HERO
if (X > 320) and (X < (40*TileW)-320-TileW) then
begin
// - 64 , because when loading the level my entire background is starting from 64 instead of 0
// looks better if there is no black line at the edge of the level...
camera_x:=(X*-1)+320-TileW;
end;
if (Y > 240) and (Y < (29*TileH)-240) then
begin
// 29 tiles down * 64 tile.height -240 half of the screen, only moving when at center of the screen
// well not really the center...but close anyway :)
camera_y:=(Y*-1)+240;
end;
if vy < 0 then
// moving up
begin
// not obstructed so move normally
y := y + vy * TimeGap
end;
if vy > 0 then
// moving down
begin
y := y + vy * TimeGap
end;
if vx < 0 then
// moving left
begin
x := x + vx * TimeGap
end;
if vx > 0 then
// moving right
begin
x := x + vx * TimeGap
end;
Collision;
end;
procedure TPlatform.DoMove(TimeGap : Double);
begin
inherited;
Collision;
end;
procedure TBlurp.DoCollision(Sprite:TSprite; var Done:boolean);
begin
if Sprite is TPlatform then
begin
//up
if vy < 0 then
begin
Y:=TPlatForm(Sprite).Y+TPlatForm(Sprite).Height;
end;
// down
if vy > 0 then
begin
Y:=TPlatForm(Sprite).Y-Height;
end;
// left
if vx < 0 then
begin
X:=TPlatForm(Sprite).X+TPlatForm(Sprite).Width;
end;
// right
if vx > 0 then
begin
X:=TPlatForm(Sprite).X-Width;
end;
end;
end;
procedure TPlatform.DoCollision(Sprite:TSprite; var Done:boolean);
begin
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AdPerCounter := TAdPerformanceCounter.Create;
AdDraw := TAdDraw.Create(self);
AdDraw.DllName := 'AndorraDX93D.dll';
if AdDraw.Initialize then
begin
Application.OnIdle := Idle;
AdImageList := TAdImageList.Create(AdDraw);
AdImageList.LoadFromFile('BackGround.ail');
//create the SpriteEngine
AdSpriteEngine := TSpriteEngine.Create(nil);
AdSpriteEngine.Surface := AdDraw;
//Create the collision tester
AdPixelCollisionTester := TAdSpritePixelCollisionTester.Create(AdDraw);
LoadLevel;
//create TImageSprite
Randomize;
Blurp := TBlurp.Create(AdSpriteEngine);
with Blurp.Create(AdSpriteEngine) do
begin
Image := AdImageList.Find('TallHero2');
X := 144;
Y := 144;
Z := 0;
CollisionTester := AdPixelCollisionTester;
end;
// The Entire Engine is moved left by -64 , this is because of the Level Loader ...
Camera_X:=-TileW;
Camera_Y:=0;
AdSpriteEngine.X:=camera_x;
AdSpriteEngine.Y:=camera_y;
// ************* hater *********************************
end
else
begin
ShowMessage('Error while initializing Andorra 2D. Try to use another display'+
'mode or use another video adapter.');
halt; //<-- Completely shuts down the application
end;
end;
procedure TForm1.Idle(Sender: TObject; var Done: boolean);
begin
if AdDraw.CanDraw then // Only continue, if drawing is possible
begin
AdPerCounter.Calculate;
AdPerCounter.MaximumFrameRate:=60;
AdDraw.ClearSurface(clBlack); // Fill the surface with black color
AdDraw.BeginScene;
// Here you need to perform all drawing operations later
ActTime := ActTime + AdPerCounter.TimeGap;
if ActTime > 10 then
begin
Blurp.vx:=0;
Blurp.vy:=0;
if GetKeyState(VK_LEFT) < 0 then
begin
Blurp.vx:=-123;
end;
if GetKeyState(VK_RIGHT) < 0 then
begin
Blurp.vx:=+123;
end;
if GetKeyState(VK_UP) < 0 then
begin
Blurp.vy:=-123
end;
if GetKeyState(VK_DOWN) < 0 then
begin
Blurp.vy:=123
end;
AdSpriteEngine.X:=camera_x;
AdSpriteEngine.Y:=camera_y;
ActTime := 0;
end;
AdSpriteEngine.Draw;
AdSpriteEngine.Move(AdPerCounter.TimeGap/1000);
AdSpriteEngine.Dead;
// debug
AdDraw.EndScene;
AdDraw.Flip; // Draws you result on the screen. Otherwise, you would not see anything
end;
Done := false; // Important, otherwise the function will not be called in every loop
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
AdSpriteEngine.Free;
AdImageList.Free;
AdPerCounter.Free;
AdDraw.Free;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key = VK_ESCAPE then Close;
end;
end.
Attached the code so you can see it in work :
test.zip
Greetings
Rob
ps.: in the next post I'll try and explain what my newer improved code does...and the parts I don't understand...
Bookmarks