PDA

View Full Version : Random based on time and not on frames



Firlefanz
08-02-2006, 09:29 AM
Hello,

I want to have some Randoms in my sprites move methods.

So the problem is if you say Random(10)=0 there,
on fast PCs it is happening more often than on slow PCs, cause higher FPS calls my move method more often.

I already have my sprites moving in dependency of time_elpased that is the time after the latest timer tick. time_elpased is>0 and <=1

time_elpase is a single;



if boolCounter then QueryPerformanceCounter(Current_Time)
else Current_Time := timeGetTime;
Time_Elapsed := (Current_Time - Last_Time) * Time_Scale;
if time_elapsed>1 then time_elapsed:=1;


So how must my random look like so it happens as often on slow PCs or fast PCs?

Something like this

if random(round(1/time_elapsed))=0 then happens each second

if random(round(2/time_elapsed))=0 then happens each 2 seconds

if random(round(0.1/time_elapsed))=0 then happens ten times a second

How is the best way that works for time_elapsed=1 but also for time_elapsed=0.001? Remember when it is 1 it is called 1 time a second, 0.001 would mean 1000 times a second, or am I wrong?

Thanks,
Firle

cairnswm
08-02-2006, 11:19 AM
Within my base sprite class I declare a virtual move function. Part of this function is calculating the time since the last move and moving the sprite based on that value.

In addition part of the move function holds a bigger counter to manage the frame count of the sprite. (I typically use a value between 150and 180 for Frames).

As long as your interval of each frame is smaller than the period being checked this is pretty accurate.


Here is an example:

procedure TShip.Move;
Var
TC : Single;
MX,MY : Integer;
begin
TC := SDL_GetTicks - LastTick;
ShootPower := ShootPower - TC;
// Do Frame Change
If SDL_GetTicks - FrameTick > 100 then
Begin
Frame := Frame + FrameOrder;
If Frame >= 15 then
Begin
Frame := 13;
FrameOrder := -1;
End;
If Frame < 0 then
Begin
Frame := 1;
FrameOrder := +1;
End;
FrameTick := SDL_GetTicks;
End;
If Keys[SDLK_UP] then
Y := Y - (TC * VSpeed);
If Keys[SDLK_Down] then
Y := Y + (TC * VSpeed);
If Keys[SDLK_RIGHT] then
X := X + (TC * (HSpeed*2))
Else
If Keys[SDLK_Left] then
X := X + (TC * (HSpeed / 2))
Else
X := X + (TC * HSpeed);
If Keys[SDLK_SPACE] and (ShootPower <= 0) then
Begin
Shoot;
End;

// Check Collisions
MX := (IX + 16) div 16;
MY := (IY + 16) div 16;
If Map.CollisionArray[MX,MY].Closed or Map.CollisionArray[MX+2,MY].Closed then
Begin
// Collision
Halt(0);
End;
LastTick := SDL_GetTicks;
end;


To expect something to happen the same on all PCs on a 0.001 second interval is expectign a bit much. I try to not go below a 0.1 second expectation.

(PS. I develop on a rather poor performing (Graphically) notebook and I make sure even it works at 30FPS - giving me a minumum resolution of 0.03 seconds for events.)

Firlefanz
08-02-2006, 11:47 AM
Hi cairnswm,

thanks for the info.

for movement every sprite has a different xspeed and yspeed and it goes like x:=x+xspeed*time_elapsed, same for y, this works perfect, they are all moving with the same speed on slow or fast FPS.

But the problem here is every sprite can shoot.
I want them to shoot manually in random intervals.

The problem is I want to have a line of code in dependency of time_elapsed that does a thing

1) one time a second
2) one time in two seconds
3) let's say 2 times a second.

Another problem is then this:
I already have some values definded for 60 different starships and want to use them without changing each one. ShootH is integer and tells how often it should shoot.
For ShootH 30 is the fastest, should shoot lets say 4 times a second, 60 should shoot only half of that 2 times a second.
This problem I have to solve after finding a solution for the above main problem, how to shoot in dependency of time_elapsed and ShootH.

Thanks,
Firle



Firle

cairnswm
08-02-2006, 12:01 PM
Store a value of last time the ship did shoot.

Each time move procedure gets called check if the expected delay has happened.

If it has, make random chance to shoot.

Set the last shoot value to now (even if the ship didn;t shoot)


If you need multiple actions store the last action times in an array and check in each cycle.

I often use an external array to store common intervals. Then what you store per ship is the index into the common array instead of storing the value.


Const
ShootInterval : Array[1..4] of Integer = (100,200,400,600);

Procedure TShip.CheckShoot;
Var
TC : Integer;
Begin
TC := SDL_GetTicks - LastShootTick;
If TC > ShootInterval[ShootType] then
Begin
LastShootTick := SDL_GetTicks;
If Random < ShootChance then
Shoot;
End;
End;


If the ship had multiple weapons I would consider modelling the weapons seperatly and then calling Weapon[I].CheckShoot in each movement step.

savage
08-02-2006, 12:02 PM
I hope I'm not missing anything obvious here, but it sounds like you need to keep track of how much time has passed before shooting, so every tick, each enemy will need to accumulate the time to know exactly how much time has passed since the last time they fired. If the accumulated time passes, that's enemy's fire rate, fire off a shot and reset the accumulation. Therefore enemy 1 can have a fire rate of once per second, while enemy 2 can have a fire rate of n per second.

I hope this helps.

savage
08-02-2006, 12:04 PM
Oops didn't see Williams post.

Firlefanz
08-02-2006, 12:18 PM
Hi,

this sounds like a good solution for my shooting problem, thanks a lot!

But I also need other random, where I cannot store the time that things last happened, for example particle stuff. Each particle does something randomly different things.

So how would a solution for the first problem look like, that random in dependency of time_elapsed?

Firle

cairnswm
08-02-2006, 12:39 PM
I use a slightly different approach for this. Basically I use a decay option. For example when the ship shoots a bullet, when can they shoot again.

Whenever an action occurs (eg Shoot) I set a ShootPower variable. Each move this Shoot Power Variable decreases (By TC in the above source example) - In the Move procedure I check if ShootPower is <= 0 and if it is I can then do the next action.

Each particle can be allocated a DecayValue. When this decay value is <= 0 then do the next random action, and set DecayValue again. To make it even more random - set DecayValue to a random value (DecayValue := Round(Random * 100) + 50).