hi
I just created a performance test for myself based on the tutorials, please let me know if someone is interested, and I will upload it with resources.
it includes:
- a group of 100 units in 10x10 formation
- one leader, the others are moving relatively to him, so obstacles are avoided, but not very smoothly
- a custom character mesh and animations converted from MTW2
- a custom map imported from L3DT (using heightmap and texture alpha maps), and some own textures
- the group can be moved together by mouse clicks on target position using the navmesh pathfinder
- free camera movements by arrows, rotate by mouse look
it's really a simple few line thingie, so do not expect intelligent behaviour, just a test. the group does not rotate due to its direction, and collisions are not handled.
probably there is a better approach for this task, but I'm really new in Esenthel engine. any idea welcome
Code:
/******************************************************************************/
#include "stdafx.h"
//#include <stdlib.h>
//#include <time.h>
/******************************************************************************
A group of custom mesh characters with own skeleton and own animation,
and with custom animation and movement speeds, in a custom world.
/******************************************************************************/
Image skybox; // sky box texture
STRUCT(Player , Game::Chr) // extend character class by defining a player class based on the character
//{
virtual void create(Game::ObjParams &obj); // override default creation method to setup custom default animations after character creation
virtual Bool update(); // here we'll update the player (please note that this is a virtual method)
// formation data
int row;
int column;
int arraynum;
};
/******************************************************************************/
Player player[100]; // player - A NEW GROUP CLASS OR STRUCT WOULD BE BETTER WITH OWN UNIT CREATOR FUNCTIONS
/******************************************************************************/
#include "../../../../../data/enum/_enums.h"
/******************************************************************************/
void Player::create(Game::ObjParams &obj)
{
super::create(obj); // call default creation
sac.stand = &cskel.getSkelAnim("obj/chr/sergeant/idle.anim");
sac.run = &cskel.getSkelAnim("obj/chr/sergeant/walk.anim");
sac.walk = &cskel.getSkelAnim("obj/chr/sergeant/walk.anim");
speed = 3;
anim.speed = 1;
}
/*******************************************************************************/
Bool Player::update()
{
// here we update character input according to mouse and keyboard
// before we set the input, we need to check if the character isn't controlled by an automatic action
if(action) // ACTION_NONE , ACTION_MOVE_TO , ACTION_MOVE_DIR
{
// if it's controlled by an action we leave the input with no changes,
// however we can optionally break that action, by pressing for example movement keys
if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
}
if(!action) // if the character isn't controlled by an automatic action, we can set the input
{
// turn & move
input.turn.x=Kb.b(KB_Q)-Kb.b(KB_E);
input.turn.y=Kb.b(KB_T)-Kb.b(KB_G);
input.move.x=Kb.b(KB_D)-Kb.b(KB_A);
input.move.z=Kb.b(KB_W)-Kb.b(KB_S);
input.move.y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);
// dodge, crouch, walk, jump
input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
input.crouch= Kb.b (KB_LSHIFT);
input.walk = Kb.b (KB_LCTRL );
input.jump =(Kb.bp(KB_SPACE) ? 3.5f : 0);
}
return super::update(); // call Game::Chr::update on which Player is based on
}
/******************************************************************************/
Game::ObjMemx<Game::Static> Statics; // container for static objects
//Game::ObjMemx<Game::Chr > Chrs; // container for item objects
Game::ObjMemx< Player> Players; // container for character objects
/******************************************************************************/
void InitPre()
{
App.name("Group of Game Characters on Terrain");
App.flag=APP_FULL_TOGGLE; // APP_MS_EXCLUSIVE| to hide mouse
DataPath("../data");
Paks.add("engine.pak");
D.full(true).hdr(false).viewRange(500).viewFov(DegToRad(60),FOV_Y); // fullscreen, hdr on, range 500, camera arc 60 degree
D.shadowMapSize(2048).shadowMapNum(4).shadowJitter(false).shadowSoft(0).shadowMode(SHADOW_MAP);
Cam.dist =10;
Cam.yaw =-PI_4; // -45° DIRECTION
Cam.pitch=-0.5f;
Cam.at.set(-50,20,-75);
}
/******************************************************************************/
Bool Init()
{
Physics.create(CSS_NONE, true, "../Installation/PhysX");
Sun.image="Env/Sky/sun.gfx";
// 1) skybox
skybox.Import("../data/Env/Sky/scube03b_clearnoon+6.tga", IMAGE_B8G8R8A8, IMAGE_CUBE);
Sky.skybox (skybox); // set sky from skybox
// 2) atmospheric sky with fog
//Sky.atmospheric();
Sky.atmosphericColor(Vec4(0.3f), Vec4(0.1f)); // horizon and sky colour
Sky.frac(0);
Sky.atmosphericDensityExponent(0.5);
Game::World.init()
.setObjType(Statics, OBJ_STATIC) // set 'Statics' memory container for 'OBJ_STATIC' objects
//.setObjType(Chrs , OBJ_CHR )
.setObjType(Players, OBJ_PLAYER);
// create the world by giving path to builded world
Game::World.New("world/mydry1.world");
Game::World.update(Cam.at);
// set water
Water.images(Images("Env/Water/0.gfx"), Images("Env/Water/0.n.gfx"), Images("Env/Water/reflection.gfx")); // set water from textures
Water.draw =true; // enable drawing
Water.wave_scale=0.8f; // adjust wave scales
Water.validate(); // must be used after manual settings
//---------------------------------------------------------
// original : from character.cpp
Game::ObjParams obj; // set object parameters
obj.mesh(true, Meshes.ptrRequire("obj/chr/sergeant/0.mesh"));
// modified : group of units
int i;
for(i=0;i<100;i++)
{
obj.matrix.setScalePos(1.8f, Vec(i%10*2-50, 10, -Int(i/10)*2-75)); // adjust height to terrain level
player[i].create(obj); // create player from object parameters
// create skeleton here, not inside void create
player[i].cskel.create(Skeletons("../data/obj/chr/sergeant/0.skel")); // create controlled skeleton from skel file, with default height
// assign animation inside void Player::create
// set speed and anim speed in void Player::create
// set player properties used for group movement - first row created from left to right
player[i].arraynum = i;
player[i].column = i%10;
player[i].row = Int(i/10);
}
//-----------------------------------------------------------
return true;
}
/******************************************************************************/
void Shut()
{
// empty
}
/******************************************************************************/
Bool Update()
{
if(Kb.bp(KB_ESC))return false;
Physics.startSimulation().stopSimulation();
// update water waves movement - requires Water.validate()
Water.update(Vec2(0.01f, 0.01f));
//------------------------------------------------------------------------------------------------
// move leader of player group
if(Ms.bp(0)) // on LMB pressed
{
Vec pos, dir; ScreenToPosDir(Ms.pos(), pos, dir); // convert screen mouse position to world position and direction
PhysHit phys_hit;
if(Physics.ray(pos, dir*D.viewRange(), &phys_hit)) // if ray-test hit something
{
player[0].actionMoveTo(Vec(phys_hit.plane.pos.x, phys_hit.plane.pos.y, phys_hit.plane.pos.z)); // order character to move to that location
}
}
//------------------------------------------------------------------------------------------------
// player group movement
Vec leaderpos = player[0].pos();
int i;
for(i=1;i<100;i++)
{
player[i].actionMoveTo(Vec(leaderpos.x+player[i].column*2,leaderpos.y,leaderpos.z-player[i].row*2));
}
//------------------------------------------------------------------------------------------------
// entity update
for(i=0;i<100;i++)
player[i].update();
//------------------------------------------------------------------------------------------------
// free camera
Cam.yaw -=Ms.d().x; // modify yaw according to mouse delta x
Cam.pitch+=Ms.d().y; // modify pitch according to mouse delta y
Cam.roll +=(Kb.b(KB_Z)-Kb.b(KB_X))*Time.d(); // modify roll according to Z and X keyboard buttons
Cam.dist -=Ms.wheel()*0.4f; // modify distance according to mouse wheel
Clamp(Cam.dist, 0.1f, 50); // clamp distance to minimum and maximum values
if(Kb.b(KB_LEFT ))Cam.at-=Cam.matrix.x*Time.d()*5; // move camera left on left arrow key
if(Kb.b(KB_RIGHT))Cam.at+=Cam.matrix.x*Time.d()*5; // move camera right on right arrow key
if(Kb.b(KB_UP ))Cam.at+=Cam.matrix.z*Time.d()*5; // move camera fwd on up arrow key
if(Kb.b(KB_DOWN ))Cam.at-=Cam.matrix.z*Time.d()*5; // move camera bckw on down arrow key
if(Kb.b(KB_HOME ))Cam.at+=Cam.matrix.y*Time.d()*5; // move camera up on Home key
if(Kb.b(KB_END ))Cam.at-=Cam.matrix.y*Time.d()*5; // move camera down on End key
Cam.setSpherical (Cam.at, Cam.yaw, Cam.pitch, Cam.roll, Cam.dist); // set spherical camera with 'look at' position, angles and distance
Cam.updateVelocities( ); // after camera settings are up, we need to update camera velocities in order to achieve correct motion blur when enabled
Cam.set ( ); // set as active camera
return true;
}
/******************************************************************************/
void Render()
{
// world.cpp
Game::World.draw(); // draw world (this is done outside of 'switch(Renderer())' because world automatically detects active rendering mode)
//-------------------------------------
int i;
switch(Renderer())
{
case RM_PREPARE:
{
for(i=0;i<100;i++)
player[i].drawPrepare();
}break;
case RM_SHADOW:
{
for(i=0;i<100;i++)
player[i].drawShadow();
}break;
}
}
void Draw()
{
Renderer(Render);
D.text(0, 0.9f, S+"Fps "+Time.fps());
}
/******************************************************************************/
Edit: I updated the screenshot, and the code too (shadows, water, sky settings)