Using Intervals to move the Panda
Intervals and Sequences
Intervals
Intervals are tasks that change a property from one value to another over a specified period of time. Starting an interval effectively starts a background process that modifies the property over the specified period of time.
Sequences
Sequences, sometimes called MetaIntervals, are a type of interval that contains other intervals. Playing a sequence will cause each contained interval to execute in sequence, one after the other.
The Program
Update the Code
The next step is to cause the panda to actually move back and forth. Update the code to the following:
1#include "pandaFramework.h"
2#include "pandaSystem.h"
3
4#include "genericAsyncTask.h"
5#include "asyncTaskManager.h"
6
7#include "cIntervalManager.h"
8#include "cLerpNodePathInterval.h"
9#include "cMetaInterval.h"
10
11// Global stuff
12PT(AsyncTaskManager) taskMgr = AsyncTaskManager::get_global_ptr();
13PT(ClockObject) globalClock = ClockObject::get_global_clock();
14NodePath camera;
15
16// Task to move the camera
17AsyncTask::DoneStatus SpinCameraTask(GenericAsyncTask *task, void *data) {
18 double time = globalClock->get_real_time();
19 double angledegrees = time * 6.0;
20 double angleradians = angledegrees * (3.14 / 180.0);
21 camera.set_pos(20 * sin(angleradians), -20.0 * cos(angleradians), 3);
22 camera.set_hpr(angledegrees, 0, 0);
23
24 return AsyncTask::DS_cont;
25}
26
27int main(int argc, char *argv[]) {
28 // Open a new window framework and set the title
29 PandaFramework framework;
30 framework.open_framework(argc, argv);
31 framework.set_window_title("My Panda3D Window");
32
33 // Open the window
34 WindowFramework *window = framework.open_window();
35 camera = window->get_camera_group(); // Get the camera and store it
36
37 // Load the environment model
38 NodePath scene = window->load_model(framework.get_models(),
39 "models/environment");
40 scene.reparent_to(window->get_render());
41 scene.set_scale(0.25, 0.25, 0.25);
42 scene.set_pos(-8, 42, 0);
43
44 // Load our panda
45 NodePath pandaActor = window->load_model(framework.get_models(),
46 "models/panda-model");
47 pandaActor.set_scale(0.005);
48 pandaActor.reparent_to(window->get_render());
49
50 // Load the walk animation
51 window->load_model(pandaActor, "models/panda-walk4");
52 window->loop_animations(0);
53
54 // Create the lerp intervals needed to walk back and forth
55 PT(CLerpNodePathInterval) pandaPosInterval1, pandaPosInterval2,
56 pandaHprInterval1, pandaHprInterval2;
57 pandaPosInterval1 = new CLerpNodePathInterval("pandaPosInterval1",
58 13.0, CLerpInterval::BT_no_blend,
59 true, false, pandaActor, NodePath());
60 pandaPosInterval1->set_start_pos(LPoint3(0, 10, 0));
61 pandaPosInterval1->set_end_pos(LPoint3(0, -10, 0));
62
63 pandaPosInterval2 = new CLerpNodePathInterval("pandaPosInterval2",
64 13.0, CLerpInterval::BT_no_blend,
65 true, false, pandaActor, NodePath());
66 pandaPosInterval2->set_start_pos(LPoint3(0, -10, 0));
67 pandaPosInterval2->set_end_pos(LPoint3(0, 10, 0));
68
69 pandaHprInterval1 = new CLerpNodePathInterval("pandaHprInterval1", 3.0,
70 CLerpInterval::BT_no_blend,
71 true, false, pandaActor, NodePath());
72 pandaHprInterval1->set_start_hpr(LPoint3(0, 0, 0));
73 pandaHprInterval1->set_end_hpr(LPoint3(180, 0, 0));
74
75 pandaHprInterval2 = new CLerpNodePathInterval("pandaHprInterval2", 3.0,
76 CLerpInterval::BT_no_blend,
77 true, false, pandaActor, NodePath());
78 pandaHprInterval2->set_start_hpr(LPoint3(180, 0, 0));
79 pandaHprInterval2->set_end_hpr(LPoint3(0, 0, 0));
80
81 // Create and play the sequence that coordinates the intervals
82 PT(CMetaInterval) pandaPace;
83 pandaPace = new CMetaInterval("pandaPace");
84 pandaPace->add_c_interval(pandaPosInterval1, 0,
85 CMetaInterval::RS_previous_end);
86 pandaPace->add_c_interval(pandaHprInterval1, 0,
87 CMetaInterval::RS_previous_end);
88 pandaPace->add_c_interval(pandaPosInterval2, 0,
89 CMetaInterval::RS_previous_end);
90 pandaPace->add_c_interval(pandaHprInterval2, 0,
91 CMetaInterval::RS_previous_end);
92 pandaPace->loop();
93
94 // Add our task.
95 taskMgr->add(new GenericAsyncTask("Spins the camera",
96 &SpinCameraTask, nullptr));
97
98 // This is a simpler way to do stuff every frame,
99 // if you're too lazy to create a task.
100 Thread *current_thread = Thread::get_current_thread();
101 while (framework.do_frame(current_thread)) {
102 // Step the interval manager
103 CIntervalManager::get_global_ptr()->step();
104 }
105
106 framework.close_framework();
107 return 0;
108}
When the pandaPosInterval1
interval is started, it will gradually adjust the
position of the panda from (0, 10, 0) to (0, -10, 0) over a period of 13
seconds. Similarly, when the pandaHprInterval1
interval is started, the
heading of the panda will rotate 180 degrees over a period of 3 seconds.
The pandaPace
sequence above causes the panda to move in a straight line,
turn, move in the opposite straight line, and finally turn again. The code
pandaPace.loop()
causes the Sequence to be started in looping mode.
Run the Program
The result of all this is to cause the panda to pace back and forth from one tree to the other.