-
Notifications
You must be signed in to change notification settings - Fork 104
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
Add pathfinding ability #119
Comments
Hi @AnotherCoolDude! Path finding would be nice but have you tried using GameplayKit? You can create a I have created a plugin that can be used to connect a import ImagineEngine
import GameplayKit
class BehaviorPlugin: NSObject, Plugin {
private let behavior: GKBehavior
private var agent: GKAgent2D?
private var actor: Actor?
private var actionToken: ActionToken?
init(behavior: GKBehavior) {
self.behavior = behavior
super.init()
}
func activate(for object: Actor, in game: Game) {
actor = object
let agent = GKAgent2D()
agent.delegate = self
self.agent = agent
// Update the values below to change how the actor moves
agent.mass = 10
agent.maxSpeed = 50
agent.maxAcceleration = 60
agent.radius = 20
agent.behavior = behavior
let updateBehaviorAction = ClosureAction<Actor>(duration: .infinity) { context in
agent.update(deltaTime: context.timeSinceLastUpdate)
}
actionToken = object.perform(updateBehaviorAction)
}
func deactivate() {
actionToken?.cancel()
actionToken = nil
actor = nil
agent = nil
}
}
extension BehaviorPlugin: GKAgentDelegate {
func agentWillUpdate(_ agent: GKAgent) {
guard let agent2d = agent as? GKAgent2D else { return }
guard let actor = actor else { return }
agent2d.rotation = Float(actor.rotation)
agent2d.position.x = Float(actor.position.x)
agent2d.position.y = Float(actor.position.y)
}
func agentDidUpdate(_ agent: GKAgent) {
guard let agent2d = agent as? GKAgent2D else { return }
guard let actor = actor else { return }
actor.rotation = Metric(agent2d.rotation)
actor.position = Point(x: Metric(agent2d.position.x), y: Metric(agent2d.position.y))
}
} Hope that helps! |
That's an awesome idea @mattiashagstrand 👍 This is exactly what the plugin system is for, so that the engine doesn't have to contain functionality like this itself, but rather things can be mixed and matched as you need them. I'd like to keep the core of the engine as thin as possible and then keep expanding the plugin API as needed to support these type of use cases. @AnotherCoolDude how does that sound? 🙂 |
I agree with you @JohnSundell, one of the big advantages of ImagineEngine is that is so easy to get started. |
That's awesome. It really shows the potential of Plugins. I agree, we should create a catalog of examples. It will boost motivation for people to get started with ImagineEngine. @mattiashagstrand thanks for the snippet, ill give it a try |
Hey guys, A question about implementing this, I tried following the comment about using gameplay kit, but I can't get it to work.. the path returns zero and then it crashes. Am I missing a step here? events.clicked.observe { scene, point in
let playerPosVector = vector_float2(x: Float(player.position.x), y: Float(player.position.y))
let posVector = vector_float2(x: Float(point.x), y: Float(point.y))
let origin = GKGraphNode2D(point: playerPosVector)
let destination = GKGraphNode2D(point: posVector)
let nodesPath = origin.findPath(to: destination)
let path = GKPath(graphNodes: nodesPath, radius: 1)
let goal = GKGoal(toFollow: path, maxPredictionTime: 100, forward: true)
let followPath = GKBehavior(goal: goal, weight: 1)
let behaviorPlugin = BehaviorPlugin(behavior: followPath)
player.add(behaviorPlugin)
} Also, would this work with obstacles? I guess that also needs to be added to GameplayKit in order to calculate them. I added them manually to the project like so let obstacules = Group.name("Obstacules")
for i in stride(from: 0, to: 10, by: 1) {
let obstacule = Block(size: Size(width: 50, height: 50), spriteSheetName: "Obstacle")
let randomPos = Metric(arc4random() % UInt32(size.width))
obstacule.position = Point(x: CGFloat(randomPos), y: CGFloat(randomPos))
obstacule.group = obstacules
add(obstacule)
}
player.constraints = [.scene, .neverOverlapBlockInGroup(obstacules)] Which works, but I guess it won't prevent the path finding from using those locations |
@raulriera What kind of crash are you getting? Yeah you need to tell GamePlayKit about your obstacles as well, since otherwise its path finding algorithm isn't aware of what zones to avoid. You should be able to create obstacles using the |
Hi @raulriera I think the reason the path returns zero is that you use the let graph = GKGraph([origin, destination])
let nodesPath = graph.findPath(from: origin, to: destination) And as @JohnSundell pointed out, you need to add the obstacles to the graph before calling I also noticed that you use |
Thanks for the help guys! I'll try it out! ❤️ |
Hey there,
i noticed an obstacle-texture in the second tutorial. I suppose you allready had the idea of implementing pathfinding in the tutorial. I tried to implement it myself with help from a guide from raywenderlich.com, but it's a bit more complex than i thought. I think pathfinding would give the engine a whole lot more capability and usefullness.
The text was updated successfully, but these errors were encountered: