Hi everyone,
I've been attempting to start my game with the Appkit as the basis for all my Lua. However, I've found that trying to work out anything to do with the Appkit is extremely tedious. I'll use what I'm currently trying to do as an example, which is set up my own Camera system as it needs a lot more functionality than what you recieve from the Appkit out of the box. I've been looking at how to create a new camera with Lua, and then set it as the active camera. Tracing the path in which the free_cam_player is created in the Appkit has left me quite confused.
I think I've narrowed down the main functions to do with creating the free_cam_player. The first is the PlayerUtil.spawn_free_cam_player() function in player_util:
function PlayerUtil.spawn_free_cam_player(level, camera_unit, camera_index, position, rotation, input_mapper) -- A container for the freecam objects local free_cam_player = {} free_cam_player.unit = camera_unit -- Camera local camera = CameraWrapper(free_cam_player, camera_unit, camera_index) camera:set_local_position(position) camera:set_local_rotation(rotation) camera:enable() -- Add camera input movement. Starts enabled. local controller = UnitController(free_cam_player, camera_unit, input_mapper) controller:set_move_speed(free_cam_move_speed:unbox()) controller:set_yaw_speed(free_cam_yaw_speed) controller:set_pitch_speed(free_cam_pitch_speed) return free_cam_player end
Obviously the next important function being the CameraWrapper() function it calls when it creates the local variable 'camera' above.. this one is from the camera_wrapper.lua:
function CameraWrapper:init(entity, unit, camera_index) self.entity = entity -- object this component is associated with, can be used to access other components self.unit = unit self.camera = Unit.camera(unit, camera_index) self.world = Unit.world(unit) self.is_enabled = false CameraWrapper.manager:add_component(entity, self, Unit.level(unit)) end
(took out a few irrelevant lines from the function above)
1) Why is the first parameter that the init function takes named 'entity'? This confuses me as I believe they're using the term to just describe a table that they've stored information in, however that's in conflict with an actual namespace 'stingray.Entity' which can just make it confusing to read.
2) When passing the 'entity' into this function, it's also passing the camera_unit as it was added to the table being passed in in the previous function here:
-- A container for the freecam objects local free_cam_player = {} free_cam_player.unit = camera_unit
so wouldn't you then just retrieve the camera_unit information from the 'entity'?
3) What IS the camera_unit? I can see it references an actual .unit file in the Appkit.. is this camera_unit used for all cameras you create? They all reference the same unit? How do you create/can you create a camera without using this?
4) The line:
self.camera = Unit.camera(unit, camera_index)
Does this just retrieve the actual Camera? i.e. the stingray.Camera object?
5) I can't see anywhere in here that the camera is actually created, only that you've made a table, storing the location of a .unit file which you then use to somehow get a camera.. but where does that camera come from? This reverts to questions 3.. what is the camera_unit?
6) How do you set the active camera? I understand the camera_wrapper.lua has this function:
function CameraWrapper:enable() if self.enabled == true then return end local world_wrapper = Appkit.managed_world if world_wrapper and world_wrapper.world == self.world then world_wrapper:set_camera_enabled(self.camera, self.unit, true) self.is_enabled = true end end
which calls this function from the world_wrapper.lua script:
function WorldWrapper:set_camera_enabled(camera, unit, enabled) if not camera then return end if enabled == true then self.enabled_cameras[camera] = unit else self.enabled_cameras[camera] = nil end end
which sets a 'camera' variable of the 'enabled_cameras' table to be the unit you pass in.. in the WorldWrapper:render() function above it, it then has this for loop:
for camera, _ in pairs(self.enabled_cameras) do Application.render_world(world, camera, viewport, shading_env) end
So I take it this means every frame you tell the renderer which camera to use, but I'm also confused because in the set_camera_enabled function we made the camera variable equal the unit.. not the actual stingray.Camera instance even though the 'Application.render_world()' function only accepts a stingray.Camera object.. Ahhh my head!! I can obviously guess since it works that somehow it actually is passing the camera instance and not a unit in but I can't figure it out.. Also, since this is for loop is running through every named key in the enabled_cameras table.. if you had multiple cameras what would happen?
I do apologise for such a long thread however answers to these questions will greatly increase my understanding of how the Appkit and Lua are working in Stingray, and I'm sure other people who are new to Stingray will also find it equally as helpful!
Thank you so much for all your help!
Cheers,
Kaine
Solved! Go to Solution.
Solved by t_livee. Go to Solution.
Hi Kaine,
All great questions! The appkit can be a bit confusing and we are continually iterating on the functionality. To answer your questions on the appkit functionality, I am going to pass this along to the person who implemented it -- also you may reference the docs here: http://help.autodesk.com/view/Stingray/ENU/?guid=__stingray_help_creating_gameplay_scripting_with_lu...
If you like, may also not use the appkit or its camera at all. In your boot.lua file you've defined, you can add in a game camera:
function init() Game.camera_unit = World.spawn_unit(Game.world, "core/units/camera") end
You can then control your camera in update, for example setting the position every tick ...
camera_pos.y = camera_pos.y + 0.5; stingray.Unit.set_local_position(Game.camera_unit, 1, camera_pos);
and in render
-- Called once every frame. function render() local camera = Unit.camera(Game.camera_unit, "camera") Application.render_world(Game.world, camera, Game.viewport, Game.shading_environment) end
I will reach out and get some further clarification on the appkit questions for you as well.
Hi Dan!
Thanks for the response! I will probably end up using a custom boot script without the Appkit when I begin a project properly, however it's a good intro to Stingray I think, and will help me to stop thinking about programming in a context I'm used to, and more in a Lua mindset..
Look forward to hearing from them.
Cheers,
Kaine
Hi Kaine! Some answers:
1. (Regarding why `CameraWrapper` arg 1 is called entity)
It's true this is a temporary system that will eventually be replaced by the stingray.Entity system. The CameraWrapper is an appkit component, that gets associated with an entity. An entity in the appkit is just a lua reference that we attach various components to. It could be a table, it could be userdata, it could be a number.
Please read the appkit docs for component_manager:
2. (regarding the camera unit argument)
There is no requirement that the `entity` object parameter must have a camera unit available on it somehow. The entity is just something we attach things to. So the camera_unit must be passed separately.
3. Yes the camera unit is the .unit file in core/appkit/units. A Camera is actually a sub-object within a Unit. A unit can have 0-n cameras in it. The Appkit camera unit has one camera in it. Cameras can be added to any unit in the Unit Editor via the Create menu, with a mesh hierarchy node selected.
4. Yes this retrieves the `Camera` engine object from the `Unit` engine object, at the given index (cameras are index from 1 to N in the unit)
5. The camera_unit for the template-based projects is created in core/appkit/lua/simple_project.lua. Then the Player scripts grab it from SimpleProject.
6. Yes engine World objects are told per render call what Camera to draw with. The Appkit offers glue (via the appkit WorldWrapper, LevelWrapper, CameraWrapper, and appkit flow nodes) to couple Cameras with Worlds so that they can be set as active either via lua or via level flow. The WorldWrapper calls render on each active camera in its list, so this can be used to do multiple viewports and other effects, but this is not used in any of our template projects.
Hey t_livee,
Thanks for the answers 🙂 I was wondering if you could clarify line 63 of the world_wrapper for me:
self.enabled_cameras[camera] = unit
Doesn't this set the variable enabled_cameras[camera] to be the unit? Not the actual camera object? How does it get the camera object when it runs through the for loop above it to call the render_world() function?
This second one is a bit of a tangent but while I've got you, are there any cases where I wouldn't use the Appkit.class script to create an 'instance' of my custom scripts, rather than just having the straight script run? Would it be good practice to always use this because then I can think of the whole program in more of an OOP sense?
Cheers,
Kaine
Edit: Is there any information out on when we can expect the entity system, or features etc that are being worked on? I think it would be great to keep hype up.
Hi Kaine!
Sorry for the delay. The WorldWrapper stores the `camera` object as the key in the table and the `camera_unit` as the value.
When the WorldWrapper iterates for rendering, it uses the camera key (and ignores the values):
for camera, _ in pairs(self.enabled_cameras) do Application.render_world(world, camera, viewport, shading_env) end
In regards to when *not* to use the class helper: when only a single instance of something is needed and the inheritance features of the class utility are not needed. It doesn't hurt much to use the class helper often however.
The exact timing on the Entity system rollout across different areas of the engine is not clear yet. There will be many systems and editor features to update.
Hey t_livee 🙂
No problem! Oh wow I can't believe I didn't see that........ thanks!
Yeah I figured there wouldn't be too much harm. I've just basically been using it for everything so I can think of the whole program in OOP terms as that's what I'm used to.
Cheers,
Kaine
Can't find what you're looking for? Ask the community or share your knowledge.