Gamestudio Links
Zorro Links
Newest Posts
MT5 bridge not working on MT5 v. 5 build 4160
by EternallyCurious. 04/25/24 20:49
Data from CSV not parsed correctly
by EternallyCurious. 04/25/24 10:20
Trading Journey
by howardR. 04/24/24 20:04
M1 Oversampling
by Petra. 04/24/24 10:34
Zorro FIX plugin - Experimental
by flink. 04/21/24 07:12
Scripts not found
by juergen_wue. 04/20/24 18:51
zorro 64bit command line support
by 7th_zorro. 04/20/24 10:06
StartWeek not working as it should
by jcl. 04/20/24 08:38
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
4 registered members (EternallyCurious, TipmyPip, Quad, AndrewAMD), 898 guests, and 7 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Mega_Rod, EternallyCurious, howardR, 11honza11, ccorrea
19048 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 3 of 3 1 2 3
Re: Reducing Function Times [Re: jumpman] #481239
08/15/20 08:58
08/15/20 08:58
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
txesmi Offline
Serious User
txesmi  Offline
Serious User

Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
Originally Posted by jumpman
Why does while(1) and wait(1); cause so many problems for lots of entities in their own loop?

They do not really cause so many. It is just a little bit slower than calling all the functions by yourself. I guess the engine probably checks something or other during the execution of the functions in the scheduler and makes it slower than raw function calls, but that is the thing of been a versatile engine, I think. A single c_move call spends many times the time taken by the scheduler for calling the action. Same happens with ent_animate. Both are pretty intensive functions and it is necessary to reduce their cost as much as possible. Building a function scheduler without taking care of these both functions is futile.

Re: Reducing Function Times [Re: Dooley] #481240
08/15/20 09:16
08/15/20 09:16
Joined: May 2009
Posts: 5,370
Caucasus
3run Offline
Senior Expert
3run  Offline
Senior Expert

Joined: May 2009
Posts: 5,370
Caucasus
I can only quote Superku, as I can't really say better than he already did:
Originally Posted by Superku
Having one game loop is the way to go IMO, so as long as your project isn't that complex already change it.
wait(1) is rather "slow" and you have no real influence on when functions are executed. proc_mode (in particular PROC_GLOBAL) is a game and project killer, leading to seemingly random crashes as it affects all kinds of functions you don't want it to have an impact on. Example:
Code
///////////////////////////////
#include <acknex.h>
#include <default.c>
///////////////////////////////

void projectile()
{
    my.skill1 = 128;
    my.pan = random(20)-10;
    my.tilt = random(20)-10;
    while(my.skill1 > 0)
    {
        c_move(me,vector(16*time_step,0,0),nullvector,0);
        my.skill1 -= time_step;
        
        VECTOR temp;
        vec_set(temp,my.x);
        if(vec_to_screen(temp,camera)) draw_text(str_printf(NULL,"%d",(int)proc_mode),temp.x,temp.y,COLOR_RED);
        
        wait(1);
    }
    ptr_remove(me);
}

void spawnProjectile()
{
    proc_mode = PROC_GLOBAL;
    wait(1); // <- doesn't help as proc_mode is restored after wait
    ent_create(CUBE_MDL,vector(0,random(16)-8,0),projectile);
}

void reload()
{
    level_load(NULL);
}

void main()
{
    fps_max = 60;
    video_mode = 10;
    level_load(NULL);
    on_mouse_left = spawnProjectile; // press left mouse button a few times,
    on_mouse_right = reload; // then the right mouse button to crash the game
}


What I've done for the past few years for new projects was to use on_frame, like this:

Code
///////////////////////////////
#include <acknex.h>
#include <default.c>

// header files
#include "player.h"

// implementation:
#include "player.c"

///////////////////////////////

void mainFrameEvent()
{
	input update function;
	if(gameMode == GAME_MODE_PLAY)
	{
		objectsUpdate();
		enemiesUpdate();
		playerUpdate();
	}
	if(gameMode == other modes) { ... }
}

void main()
{
	fps_max = 60;
	level_load(NULL);
	...
	on_frame = mainFrameEvent;
}


This way you have complete control over what gets executed when and how. You could for example freeze all enemies or projectiles in the game with a simple if(variable) check, while allowing the player to move freely.
You only have to let's say create a list of objects after level_load (on_level_load or what it's called) and free that list on or before level change.

I still use wait(1) entity loops here and there but just for some level decoration/ dynamic objects which don't have an actual influence on gameplay.
And
Originally Posted by Superku
Sorry, but you are wrong. A big project is super tough to manage and debug when using wait. The initial setup is a little easier but that's about it, no other advantages, only disadvantages.
Btw. 10000 waits eat up 2ms of performance already on a 6700k. You'd have to do one hell of an optimization to save 2ms normally, or you could just NOT use wait.

And also a test results performed by txesmi in the past:
Originally Posted by txesmi
The only way of speaking about the offtopic is with numbers.

[Linked Image]

Code
-----------------------------------------
| a wait per entity | own scheduler     |
| 1 byte stack      | 1 byte stack      |
-----------------------------------------
| a wait per entity | own scheduler     |
| 128 bytes stack   | 128 bytes stack   |
-----------------------------------------

Notice that the stack memory size has also its impact in the difference.


Code
#include <acknex.h>
#include <default.c>

#define ENT_COUNT    10000
#define STACK_SIZE   1
#define COMPLEXITY   1

ENTITY *ents[ENT_COUNT];

action actWait() {
	BYTE _n[STACK_SIZE];
	while(1) {
		int _i = 0;
		for(; _i<COMPLEXITY; _i+=1)
			_n[random(STACK_SIZE)] = random(256);
		wait(1);
	}
}

var actList(ENTITY *_ent) {
	BYTE _n[STACK_SIZE];
	int _i = 0;
	for(; _i<COMPLEXITY; _i+=1)
		_n[random(STACK_SIZE)] = random(256);
	return -1;
}

void entLoop () {
	while(!key_esc) {
		wait(1);
		ENTITY **_ent = ents;
		ENTITY **_entLast = _ent + ENT_COUNT;
		for(; _ent<_entLast; _ent++) {
			if(*_ent == NULL)
				continue;
			var _result = actList(*_ent);
			if(_result == 0)
				continue;
			switch(_result) {
				case 1:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 2:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 3:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 4:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 5:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 6:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 7:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 8:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 9:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 10:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 11:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 12:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 13:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 14:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 15:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 16:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 17:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 18:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 19:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				default:
					break;
			}
		}
	}
}

void main () {
	max_entities = ENT_COUNT;
	
	void _act ();
	_act = actWait;
//	_act = actList;
	
	level_load("");
	def_debug();
	int _i = 0;
	for(; _i<ENT_COUNT; _i+=1)
		ents[_i] = ent_create(SPHERE_MDL, vector(0, 0, -1000), _act);
	if(_act == actList)
		entLoop();
}


I gived a bit of complexity to the scheduler loop so it can be considered a complete flux manager. The numbers speak by themself. It is clear it gains performance with a single while loop but it is not that much. Take into account that we are speaking about a difference of 3/10000 ms/ent: the time taken by few operations. Bad programming practices will waste more time.

Salud!

Greets!


Looking for free stuff?? Take a look here: http://badcom.at.ua
Support me on: https://boosty.to/3rung
Re: Reducing Function Times [Re: 3run] #481241
08/15/20 09:54
08/15/20 09:54
Joined: Sep 2009
Posts: 993
Budapest
Aku_Aku Offline
User
Aku_Aku  Offline
User

Joined: Sep 2009
Posts: 993
Budapest
Nice collection of thoughts 3run!

Page 3 of 3 1 2 3

Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1