-
Notifications
You must be signed in to change notification settings - Fork 1
/
joystick_example.py
150 lines (133 loc) · 5.27 KB
/
joystick_example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from __future__ import division
from direct.showbase.ShowBase import ShowBase
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import ActorNode
from panda3d.core import NodePath, LVector3, KeyboardButton
import sys
try:
import pygame
except ImportError:
pygame = False
print 'Pygame not found, necessary for joystick use'
class JoystickWorld(DirectObject):
# a bit of a strange example of joystick use, because there is no acceleration, and movement
# is literal (forward forward, left is left, etc), iow no turning, no looking around. this is
# due to the strange game this code eventually went into, but still a useful example of using
# joystick and/or keyboard for movement. Eventually I would like to use this to show different
# examples of movement, but at least we see basic implementation, as is.
def __init__(self, config=None):
DirectObject.__init__(self)
# joystick
js_count = 0
self.joystick = None
if pygame:
pygame.init()
js_count = pygame.joystick.get_count()
if js_count > 1:
raise NotImplementedError("More than one Joystick is connected")
elif js_count == 1:
self.joystick = pygame.joystick.Joystick(0)
print 'Using joystick'
self.joystick.init()
# print self.joystick.get_numaxes()
# threshold for joystick
self.threshold = 0.1
else:
print 'No joystick found'
# print('joystick', self.joystick)
self.last_avt = [0, 0]
self.map_avt_node = []
# need a multiplier to the joystick output to make tolerable speed
self.vel_base = 5
self.max_vel = [500, 500, 0]
self.base = ShowBase()
self.base.disableMouse()
self.velocity = LVector3(0)
# environment
self.environ = self.base.loader.loadModel("models/environment")
self.environ.reparent_to(self.base.render)
# create the avatar
self.avatar = NodePath(ActorNode("avatar"))
self.avatar.reparentTo(self.base.render)
self.avatar.setH(self.base.camera.getH())
self.base.camera.reparentTo(self.avatar)
self.base.camera.setPos(0, 0, 0)
self.avatar.setPos(-10, -10, 2)
self.setup_inputs()
self.frameTask = self.base.taskMgr.add(self.frame_loop, "frame_loop")
self.frameTask.last = 0 # task time of the last frame
# print 'end init'
def frame_loop(self, task):
dt = task.time - task.last
task.last = task.time
self.poll_joystick()
self.poll_keyboard()
self.move_avatar(dt)
return task.cont
def poll_joystick(self):
if not self.joystick:
return
# joystick input -1 to 1,
# if I get the event, it only has a signal when
# there is movement, so loop through the events,
# to collect events into axis call, but call
# axis after, since it will stay at whatever the
# last signal was, instead of zeroing out whenever
# no movement. Much more convenient that way.
for event in pygame.event.get():
pass
x = self.joystick.get_axis(0)
y = self.joystick.get_axis(1)
# if both are under threshold, assume noise
# if one is deliberate, noise in the other won't affect much
if -self.threshold < x < self.threshold and -self.threshold < y < self.threshold:
# print 'threshold'
# print 'x', x, 'y', y
self.velocity.x = 0
self.velocity.y = 0
else:
self.velocity.x = x
self.velocity.y = -y
def poll_keyboard(self):
# under normal circumstances, use median of joytick output
x_speed = 0.5
y_speed = 0.5
# checks keyboard, not mouse, in this case
is_down = self.base.mouseWatcherNode.is_button_down
if not self.joystick:
self.velocity.x = 0
self.velocity.y = 0
if is_down(KeyboardButton.up()):
self.velocity.y += y_speed
if is_down(KeyboardButton.down()):
self.velocity.y -= y_speed
if is_down(KeyboardButton.left()):
self.velocity.x -= x_speed
# print 'keyboard'
if is_down(KeyboardButton.right()):
self.velocity.x += x_speed
def move_avatar(self, dt):
# print 'velocity', self.velocity
# this makes for smooth (correct speed) diagonal movement
# print 'velocity', self.velocity
magnitude = max(abs(self.velocity[0]), abs(self.velocity[1]))
if self.velocity.normalize():
# go left in increasing amount
# print 'dt', dt
# print 'normalized'
# print 'velocity', self.velocity
# print 'magnitude', magnitude
self.velocity *= magnitude
# print 'velocity', self.velocity
# this makes for smooth movement
move = self.velocity * self.vel_base * dt
# print move
self.avatar.setFluidPos(self.avatar, move)
def setup_inputs(self):
self.accept('q', self.close)
def close(self):
pygame.quit()
sys.exit()
if __name__ == "__main__":
JW = JoystickWorld()
JW.base.run()