Relative touch

Hi, so I’m experimenting with a relative touch version of Starsceptre

It’s easy to get the ship to follow my finger if I use:

 sh.x=touch.x
sh.y=touch.y

sh.x is the x position of the Ship
sh.y if the y postition of the ship

I’m looking to implement a couple of lines of code that moves the ship relative to where you finger is. So if the ship starts off in the middle of the screen, when I Touch I want it to work out it’s relative position to the ship and when I move adjust the x of the ship accordingly. Currently it just snaps to the position of the touch.

I’ve been wracking my brain and not been able to work out the code. Can anyone help?

Thanks
Rich

Are you after something like this or did I not understand what you’re after.

displayMode(FULLSCREEN)

function setup()
    sx,sy,dx,dy=WIDTH/2,HEIGHT/2,0,0
end

function draw()
    background(40, 40, 50)
    sprite("Tyrian Remastered:Evil Orb",sx-dx,sy-dy)
end

function touched(t)
    if t.state==BEGAN then
        tx,ty=t.x,t.y
    elseif t.state==MOVING then
        dx,dy=tx-t.x,ty-t.y
    elseif t.state==ENDED then
        sx,sy,dx,dy=sx-dx,sy-dy,0,0
    end
end

THanks @dave1707 - that works great. I’m just gonna look into how it works to help my head ! Lol. Thank you

Hey @dave1707 - so I understand that code well now. Great piece of code.

What I’m finding is if you touch a second finger it interrupts the code and the ship jumps around. So I’m looking to define a single touch, then multiple touch is to be ignored by this code.

@Majormorgan Try this.

displayMode(FULLSCREEN)

function setup()
    sx,sy,dx,dy,td=WIDTH/2,HEIGHT/2,0,0,0
end

function draw()
    background(40, 40, 50)
    sprite("Tyrian Remastered:Evil Orb",sx-dx,sy-dy)
end

function touched(t)
    if t.state==BEGAN and td==0 then
        tx,ty,td=t.x,t.y,t.id
    elseif t.state==MOVING and td==t.id then
        dx,dy=tx-t.x,ty-t.y
    elseif t.state==ENDED and td==t.id then
        sx,sy,dx,dy,td=sx-dx,sy-dy,0,0,0
    end
end

A small adjustment to use vec2s:

displayMode(FULLSCREEN)

function setup()
    position = vec2(WIDTH/2,HEIGHT/2)
end

function draw()
    background(40, 40, 50)
    sprite("Tyrian Remastered:Evil Orb",position.x,position.y)
end

function touched(t)
    if t.state==BEGAN and not tid then
        offset = position - vec2(t.x,t.y)
        tid = t.id
    elseif tid and tid==t.id then
        position = vec2(t.x,t.y) + offset
        if t.state == ENDED then
            tid = nil
        end
    end
end

Here’s a way using vec3’s, but it’s a little confusing.

displayMode(FULLSCREEN)

function setup()
    ship=vec3(WIDTH/2,HEIGHT/2,0)
end

function draw()
    background(40, 40, 50)
    sprite("Tyrian Remastered:Evil Orb",ship.x,ship.y)
end

function touched(t)
    if t.state==BEGAN and ship.z==0 then
        diff=ship-vec3(t.x,t.y,t.id)
    elseif t.state==MOVING and math.abs(diff.z)==t.id then
        ship=vec3(t.x,t.y,0)+diff
    elseif t.state==ENDED and math.abs(diff.z)==t.id then
        ship.z=0
    end
end

@dave1707 I really do not recommend using vec3s. If you want to combine the data into a single object, use a table.

displayMode(FULLSCREEN)

function setup()
    ship={
        position = vec2(WIDTH/2,HEIGHT/2)
        offset = vec2(0,0),
        inTouch = false,
        sprite = "Tyrian Remastered:Evil Orb"
     }
end

function draw()
    background(40, 40, 50)
    sprite(ship.sprite,ship.position.x,ship.position.y)
end

function touched(t)
    if t.state==BEGAN and not ship.inTouch then
        ship.inTouch = true
        ship.offset = self.position - vec2(t.x,t.y)
        ship.touchid = t.id
    end
    if ship.inTouch and ship.touchid == t.id then 
        ship.position = vec2(t.x,t.y) + ship.offset
        if t.state == ENDED then
            ship.inTouch = false
        end
    end
end

But of course, by this stage you may as well introduce a class.

Ship = class()

function Ship:init(p,s)
    self.position = p
    self.sprite = s
end

function Ship:draw()
    sprite(self.sprite, self.position.x,self.position.y)
end

function Ship:touched(t)
    if not self.inTouch then
        self.offset = self.position - vec2(t.x,t.y)
        self.inTouch = true
        self.touchid = t.id
        return true
    end
    if not self.touchid == t.id then
        return false
    end
    self.position = vec2(t.x,t.y) + self.offset
    if t.state == ENDED then
        self.inTouch = false
    end
    return true
end

function setup()
    ship = Ship(vec2(WIDTH/2,HEIGHT/2), "Tyrian Remastered:Evil Orb")
end

function draw()
    background(40,40,50)
    ship:draw()
end

function touched(t)
    if ship:touched(t) then
        return
    end
end

@LoopSpace For this purpose, a vec3 worked just fine. Would I use a vec3 or vec4 to hold different variables, probably not, but then it would depend on what I was doing. As I said above, it’s a little confusing mixing the vec3 data and having to take the absolute value of the Touch ID to get it to work. Using a table or a class works, but those use more code compared to what is actually needed. The above examples just show that there are different ways to accomplish the same thing. It just depends on your coding style and what you’re used to.

@dave1707 Different coding styles is fine, but I don’t think that co-opting a vec3 or vec4 like that is good style. It implies a relationship between the components that doesn’t exist. Using a table is hardly any more code but keeps the relationship of the different pieces clear.

@LoopSpace Like I said, it all depends on your coding style. Would I mix data in a vec for a production program, no. Would I mix data in a vec just to show it can be done, yes. My days of production programming are long gone, but my days of hacked programming is still going on. Right now I’m a lazy programmer. In my examples I use a lot of abbreviated names (a couple of characters long) just so I don’t have to type much. I don’t expect someone to take my code and use it in their code without understanding what it does and changing the variable names to something that they understand. A lot of times I rewrite code just to make it as small as possible just to do it. I wouldn’t consider myself a good teacher.

@dave1707 But people do take your code and work with it since you provide so many examples, often without really understanding it. So you really ought to consider all your code here as “production programming”. There are lots of things that “can be done”, but shouldn’t be and without any commentary then people who don’t know better are going to think that that is a good idea.

@LoopSpace You’re probably correct, I should do a better job with my examples. As I said, I’m not a very good teacher and I’m a lazy programmer and I probably won’t change. Even when I was working I never commented my code even though I was told more than once to do so. I always said that the code was the comments because it was always correct and current.

Thanks @dave1707 and @LoopSpace these are really cool

Currently I can using the version before Vec2 onwards was introduced. This works great for me.

Now one thing I would love to have is based on how fast I move the finger left or right I’d like to measure that change so I can switch the state of the ship to another state. Currently the ship is in flat mode. When you start to move slowly right it tilts right (I have the animation code already for that) and if you move faster right it goes to extreme tilt right.

Ignore calling the states, for decidImg how far I’ve dragged do I use touch.delta?

Thanks and Merry Christmas!!!

@Majormorgan You can use t.deltaX to determine how fast you’re moving your finger. Each call to the touched function MOVING will give you how far your finger moved.

Works a treat @dave1707 - perfect!

One other question. When the ship dies some of the touches are still engaged and play up on the next life. Is there a way to reset all that touches?

Thanks and merry Christmas!!

Are you saving the touches in a table. If so, when the ship dies just set the table to nil and start over.

Perfect. Thank you @dave1707 I’m really starting to understand this stuff. Got it saving to a table and wiping that when I start over. Perfect

Complete novice, so forgive the stupid question.

I”m using the vec2 ship class example above and believe I understand how it works, but when I try and do it over a background image, or at least how I think that should be done after searching on here, instead of getting a moving ship, I get the image I used for the background replacing the ship and that moves instead!

The only difference in the draw function is the sprite command below (I setup the image variable in setup.

Could someone enlighten me please so I get a moving ship, not a pictur…?

function draw()

background(40, 40, 50)
-- Set background
sprite(imageBackground, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)

-- Do your drawing here
ship:draw()

end

@RaggedTooth Heres the ship code along with the star background.

displayMode(FULLSCREEN)

function setup()
    tab={}
    for z=1,300 do  -- number of stars
        x=math.random(WIDTH)
        y=math.random(HEIGHT)
        s=math.random(8)    -- size
        sp=math.random(3)   -- speed
        c=color(math.random(255),math.random(255),math.random(255))
        table.insert(tab,{x=x,y=y,s=s,sp=sp,c=c})
    end   
    ship = Ship(vec2(WIDTH/2,HEIGHT/2), "Tyrian Remastered:Evil Orb")
end

function draw()
    background(40,40,50)
    for a,b in pairs(tab) do
        fill(b.c)
        ellipse(b.x,b.y,b.s)
        b.y=b.y-b.sp
        if b.y<-10 then
            b.y=HEIGHT+20
        end
    end
    ship:draw()
end

function touched(t)
    if ship:touched(t) then
        return
    end
end

Ship = class()

function Ship:init(p,s)
    self.position = p
    self.sprite = s
end

function Ship:draw()
    sprite(self.sprite, self.position.x,self.position.y)
end

function Ship:touched(t)
    if not self.inTouch then
        self.offset = self.position - vec2(t.x,t.y)
        self.inTouch = true
        self.touchid = t.id
        return true
    end
    if not self.touchid == t.id then
        return false
    end
    self.position = vec2(t.x,t.y) + self.offset
    if t.state == ENDED then
        self.inTouch = false
    end
    return true
end