-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Game controller support #717
base: master
Are you sure you want to change the base?
Conversation
… the window when clicking the buttons
…ing for button press detection on windows
… check in the process
Allow saving and configuring gamepad mappings Add gamepad sensitivity, for camera only Adjust multipliers in usage of gamepad axes Prompt for downloading controller mappings, and allow configuration
… duplicate code, or have to detect if startup has finished
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked through the entire code yet, but about half-way through I discovered that I keep repeating myself, so please apply my comments to the remaining code.
I mainly highlighted some syntax changes to simplify the code or make it less error prone.
Most notably, please use defer
.
Also I would suggest to use the stackAllocator for all local allocations. It's much faster than using the global allocator.
And finally: Only OutOfMemory errors are unreachable. Other errors, like for file and network code can be reached by e.g. missing network connection or incorrect file permission. These errors must be handled and printed, otherwise we end up in hard to debug situations where the game just crashes and we have no idea why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for taking so long to review.
I still think you could do some improvements here.
Could also explain the intentions behind this new cursor you added?
src/graphics/Window.zig
Outdated
const Gamepad = struct { | ||
gamepadState: std.AutoHashMap(c_int, *c.GLFWgamepadstate) = undefined, | ||
controllerMappingsDownloaded: bool = false, | ||
controllerMappingsTask: ?ControllerMappingDownloadTask = null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this has only one instance, you might as well just make these public variables.
src/graphics/Window.zig
Outdated
self.gamepadState.put(jid, main.globalAllocator.create(c.GLFWgamepadstate)) catch unreachable; | ||
} | ||
_ = c.glfwGetGamepadState(jid, self.gamepadState.get(jid).?); | ||
const oldState: c.GLFWgamepadstate = oldGamepadState orelse std.mem.zeroes(c.GLFWgamepadstate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you even have these twice, like you can just store the std.mem.zeroes(c.GLFWgamepadstate)
in oldGamepadState
and not make it optional.
key.value = newAxis; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it's almost the exact same code as 65-121
Is it possible to combine these into one?
It seems to be more error prone the way it is right now. For example you forgot to apply the deadzone in this version.
src/graphics/Window.zig
Outdated
} | ||
if(GLFWCallbacks.currentPos[1] >= winSize[1]) { | ||
GLFWCallbacks.currentPos[1] = winSize[1] - 1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need to write it this verbose. What you are doing here is just a clamp on a vector. You can use std.math.clamp for that.
src/graphics/Window.zig
Outdated
} | ||
const ControllerMappingDownloadTask = struct { // MARK: ControllerMappingDownloadTask | ||
curTimestamp: i128, | ||
controllerMappingsDownloaded: *bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This construct seems a bit weird.
Instead of scheduling multiple tasks and removing the duplicate ones after the first one finished, you should just not schedule multiple tasks in the first place. This should be simpler to implement too.
(also for atomics it would be better ot use std.atomic.Value, to make this more type safe)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already had it so that it doesn't schedule multiple tasks, but in a different function. I'll add this to the schedule function as well.
src/graphics/Window.zig
Outdated
if (files.openDir(".") catch null) |dir| { | ||
var _dir: files.Dir =dir; | ||
if (_dir.hasFile("gamecontrollerdb.stamp")) { | ||
const stamp = _dir.read(main.globalAllocator, "gamecontrollerdb.stamp") catch unreachable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error is not unreachable! The file might for example have incorrect permissions.
also: stackAllocator
src/graphics/Window.zig
Outdated
timestamp = newTimestamp; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here a block would be more readable in my opinion:
const timestamp: i128 = blk: {
var dir = files.openDir(".") catch break :blk 0;
if(!dir.hasFile(...)) break :blk 0;
const stamp = _dir.read(main.stackAllocator, "gamecontrollerdb.stamp") catch break :blk 0;
defer main.stackAllocator.free(stamp);
break :blk std.fmt.parseInt(i128, stamp, 16) catch 0;
};
src/graphics/Window.zig
Outdated
pub fn init() *Gamepad { | ||
const self: *Gamepad = main.globalAllocator.create(Gamepad); | ||
if (!settings.askToDownloadControllerMappings) { | ||
self.*.downloadControllerMappings(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to do .* when accessing members of a pointer.
This is Zig, not C/C++.
src/graphics/Window.zig
Outdated
self.*.downloadControllerMappings(); | ||
} | ||
self.*.updateControllerMappings(); | ||
self.*.gamepadState = std.AutoHashMap(c_int, *c.GLFWgamepadstate).init(main.globalAllocator.allocator); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of the new zig version that I updated to recently, you can just use
self.*.gamepadState = .init(main.globalAllocator.allocator);
This pull request adds controller support to the game.
TODO: