How to use Minter? I need VirtualStick and TapAction.
I can’t get this to copy on my iPad no matter what method I use. Can someone email it to Posterous.com? It would be much appreciated.
Have same problem with copying file!
Great work!
Maybe i had to add this to Monster
Thanks! This is definitely useful.
Can somebody Post it in posterous? Cant manage to Download it
Look up a few comments - Alex812a posted it.
I’ve put a downloadable package of the latest code here: http://npryce-codea.posterous.com/controllers
And examples are here: https://github.com/npryce/codea-controllers
Thanks, I used it in my Hunter game.
It’s fantastic. Thank you, Nat.
I can’t figure out how to use it to make a dual stick shooter I’m having a hard time to make it fire. Can someone help me?
Great code but I am a little confused. How code would look like if I want 2 stick in singleplayer mode??
Have a look at: https://github.com/npryce/codea-controllers/blob/master/MultiplayerExample.lua
This uses two sticks to control two player characters but you could make one stick move the player and one stick control the shooting direction.
Wow, this is so cool… can this be added as a native feature of the Codea app (in a future update)?
Thank you @nat. I wish there was an example for each of you great controllers in a single main file… Do you plan to do one? Or do you want me to do one? (i’ll have to do it anyway if i want to understand how your tools work)
I did have a big demo program that used lots of different controllers but I think it was rather confusing. So I wrote several small demos instead. More demo programs would be good but I think keeping them very very tiny is better, so that the use of the controllers is not obscured by the rest of the program.
Ok. I forgot to mention: i love your idea of a controller that appears only where needed (the touch position) and when needed: it doesn’t spoil the screen pixels then. Even their look is that way: minimum drawing, very elegant. Great job.
Hello all. I have modified Nat’s controllers to gain in FPS by drawing the controlls in an image and drawing them as a sprite. But i ran into a bug i cannot find the source: the first drawing i do by setContext(myImage) is ok but the next ones are distorded in the x axis (not the y!). I cannot find the mistake i made. Is is a codea bug? It seems to be linked to the displayMode. Thanks for your help.
--# Main
-- Moving a sprite with a VirtualStick
function setup()
displayMode(FULLSCREEN)
pos = vec2(WIDTH/2, HEIGHT/2)
steer = vec2(0,0)
speed = 400 -- pixels per second
controller1 = VirtualStick {
moved = function(v) steer = v end,
released = function(v) steer = vec2(0,0) end
}
controller1:activate({x0=0.5,x1=1,y0=0,y1=0.25,name="moving stick1"})
controller2 = VirtualStick {
moved = function(v) steer = v end,
released = function(v) steer = vec2(0,0) end
}
controller2:activate({x0=0.5,x1=1,y0=0.25,y1=0.50,name="moving stick 2"})
controller3 = VirtualStick {
moved = function(v) steer = v end,
released = function(v) steer = vec2(0,0) end
}
controller3:activate({x0=0.5,x1=1,y0=0.5,y1=0.75,name="moving stick 3"})
allControllers = All({controller1,controller2,controller3,controller4})
end
function draw()
background(131, 228, 73, 255)
pos = pos + steer*speed*DeltaTime
sprite("Planet Cute:Character Boy", pos.x, pos.y)
allControllers:draw()
end
function touched(touch)
allControllers:touched(touch)
end
--# Controller
-- Base class for controllers
Controller = class()
function Controller:activate(input)
local x0 = input.x0 or 0
local x1 = input.x1 or 1
local y0 = input.y0 or 0
local y1 = input.y1 or 1
self.cx = (x0+x1)/2 *WIDTH
self.cy = (y0+y1)/2 *HEIGHT
self.wx = (x1-x0)/2 *WIDTH
self.wy = (y1-y0)/2 *HEIGHT
self.name = input.name
end
function Controller:demo(timeout)
if ElapsedTime<timeout then
pushStyle() pushMatrix()
strokeWidth(1)
rectMode(RADIUS)
fill(255, 16, 0, 123)
rect(self.cx,self.cy,self.wx,self.wy)
fill(255, 255, 255, 255)
fontSize(20)
text("region of activation of",self.cx,self.cy+20)
text(self.name,self.cx,self.cy - 20)
popStyle() popMatrix()
end
end
function Controller:check(touch)
local goodZone = false
if math.abs((touch.x-self.cx))<self.wx
and math.abs((touch.y-self.cy))<self.wy
then
goodZone = true
end
return goodZone
end
function Controller:draw()
-- nothing
end
-- Utility functions
function touchPos(t)
return vec2(t.x, t.y)
end
function clamp(x, min, max)
return math.max(min, math.min(max, x))
end
function clampAbs(x, maxAbs)
return clamp(x, -maxAbs, maxAbs)
end
function clampLen(vec, maxLen)
if vec == vec2(0,0) then
return vec
else
return vec:normalize() * math.min(vec:len(), maxLen)
end
end
-- projects v onto the direction represented by the given unit vector
function project(v, unit)
return v:dot(unit)
end
function sign(x)
if x == 0 then
return 0
elseif x < 0 then
return -1
elseif x > 0 then
return 1
else
return x -- x is NaN
end
end
function doNothing()
end
--# Controller_VirtualStick
VirtualStick = class(Controller)
function VirtualStick:init(args)
self.radius = args.radius or 100
self.deadZoneRadius = args.deadZoneRadius or 25
self.releasedCallback = args.released or doNothing
self.steerCallback = args.moved or doNothing
self.pressedCallback = args.pressed or doNothing
-- pre-draw sprites
self.base = self:createBase()
self.stick = self:createStick()
end
function VirtualStick:createBase()
local base = image(self.radius*2+6,self.radius*2+6)
pushStyle() pushMatrix()
ellipseMode(RADIUS)
strokeWidth(1)
stroke(255, 255, 255, 255)
noFill()
setContext(base)
background(0, 0, 0, 0)
ellipse(base.width/2, base.height/2, self.radius, self.radius)
ellipse(base.width/2, base.height/2, self.deadZoneRadius, self.deadZoneRadius)
setContext()
popMatrix() popStyle()
return base
end
function VirtualStick:createStick()
local base = image(56,56)
pushStyle() pushMatrix()
ellipseMode(RADIUS)
strokeWidth(1)
stroke(255, 255, 255, 255)
noFill()
setContext(base)
background(0, 0, 0, 0)
ellipse(base.width/2, base.height/2, 0.75*25, 25)
setContext()
popMatrix() popStyle()
return base
end
function VirtualStick:touched(t)
local pos = touchPos(t)
local goodZone = self:check(t)
if t.state == BEGAN and self.touchId == nil and goodZone then
self.touchId = t.id
self.touchStart = pos
self.stickOffset = vec2(0, 0)
self.pressedCallback()
elseif t.id == self.touchId then
if t.state == MOVING then
self.stickOffset = clampLen(pos - self.touchStart, self.radius)
self.steerCallback(self:vector())
elseif t.state == ENDED or t.state == CANCELLED then
self:reset()
self.releasedCallback()
end
end
end
function VirtualStick:vector()
local stickRange = self.radius - self.deadZoneRadius
local stickAmount = math.max(self.stickOffset:len() - self.deadZoneRadius, 0)
local stickDirection = self.stickOffset:normalize()
return stickDirection * (stickAmount/stickRange)
end
function VirtualStick:reset()
self.touchId = nil
self.touchStart = nil
self.stickOffset = nil
end
function VirtualStick:draw()
if self.name ~= nil then self:demo(10) end
if self.touchId ~= nil then
sprite(self.base,self.touchStart.x, self.touchStart.y)
sprite(self.stick,
self.touchStart.x+self.stickOffset.x,
self.touchStart.y+self.stickOffset.y)
end
end
--# Controller_All
-- Forwards each touch event to all the controllers in the table
-- passed to the constructor
All = class(Controller)
function All:init(controllers)
self.controllers = controllers
end
function All:touched(t)
for _, c in pairs(self.controllers) do
c:touched(t)
end
end
function All:draw()
for _, c in pairs(self.controllers) do
c:draw()
end
end
I don’t have time to check it right now, but the first thing I would do is take displayMode(FULLSCREEN) out of setup() and put it by itself at the top of your code. Weird bugs can happen when certain things are not at the very beginning of the code before setup().