Log In  

Hi everyone,

I got inspired by the 1-Bit Clicker jam to experiment with a new game and have an issue with a single mouse click being active for a few frames while I would like it to behave just like BTNP where the click stops registering on the next frame until I press it again.

Hope that makes sense :)

Thanks for your help.

K.

P#39542 2017-04-11 10:37 ( Edited 2017-04-13 15:51)

2

So you don't want your action to be played when the mouse button is on, but only when it goes from off to on. Just a hint ;).
If you need more:


You need 2 vars:

  • one set to the previous button state (old_bton)
  • one set to the current button state (bton=true when button pressed, false otherwise)
    If old_bton==false and bton==true, you got it.
P#39549 2017-04-11 16:16 ( Edited 2017-04-11 20:25)

I just added mouse support to my framework. You could take a look through that to see how I accomplish presses and releases for the mouse. If you don't want to make it yourself, feel free to use the starter project. It saves a bunch of time doing low-level crap.

https://github.com/brandonschmeidler/pico8_starter

P#39554 2017-04-11 19:16 ( Edited 2017-04-11 23:17)

ElGregos > Thanks for the tip, that's the kind of challenge I'm up for and it'll help my understanding of code better.

I actually tried it but missed something, here's the link to the WIP if you can point me to the right direction:
>>https://www.lexaloffle.com/bbs/?tid=29153

I've use clkp (pressed) and clkr(released) for the variables you mentioned.

I couldn't find a way to switch from one state to another, as it is now, it takes into account clkp==false and clkr==true but it's the default state before I start clicking.

Thanks a lot for your help again.


Hippyman > Thanks a lot man, just looked at it and since I'm still new to programming I wasn't able to make complete sense of the mouse system though I'll definitely play with your framework once I get some basics down.

P#39562 2017-04-12 06:12 ( Edited 2017-04-12 10:12)

If I got it right, you want the sprite to disappear when you click on it, but for now it does the opposite. This is a problem you can easily solve, with even no need to consider the "do it when the mouse is pressed only if it was not pressed the frame before" point, as the issue is somewhere else.

You have 2 variables to check the mouse being pressed (clkp) or released (clkr), but obviously when the mouse is pressed, it is not released, and vice versa. So you only need one boolean instead of two: clkp, which is true if mouse is pressed, false if released. No need for clkr.

Then you can simplify your test in clkattack function, which is wrong btw, as for now it returns true if the mouse is not pressed and is released (with that superfluous test as said above).

So you need to get rid of that useless variable. Then change the test to return the right boolean. But if you think a bit further, you'll see this clkattack function needs no tests, you just have to return a value. Can't be simpler :)

Btw, a tip for checking booleans. Your way is working, no pb, but it can be even simpler, shorter, token-friendly and easier to read. For example your test

if clkp==false and clkr==true then

can be rewritten as

if not clkp and clkr then
P#39563 2017-04-12 08:00 ( Edited 2017-04-12 12:00)

Thanks a lot for getting back at me, actually what you suggested was in my previous build.

I reverted it back to it so you can see the issue with the frame rate. In order to kill the enemy I'm using the HP as a counter, but because the mouse click pressure happens in more than a frame, it drains the HP too quickly.

The boolean check tip is great (learning everyday!) ;)

Here's the update (or revert):
https://www.lexaloffle.com/bbs/?tid=29153

Cheers.

K.

P#39568 2017-04-12 10:18 ( Edited 2017-04-12 14:18)

Ok, then I'll use this boolean tip, beware! First let's simplify again your code:

function clkattack()
 if not clk then
  return false
 else
  return true
 end
end

There's no need testing a boolean to return another boolean. Considering you want to return false when clk is not true, your test is like

function clkattack()
 if not true then
  return false
 else
  return true
 end
end

and as you know not true == false, so you have

function clkattack()
 if false then
  return false
 else
  return true
 end
end

Then how about having just

function clkattack()
 return clk
end

If to the opposite you want to get true when clk is false, just return the opposite of the boolean, which is "not" :

function clkattack()
 return (not clk)
end

Parentheses are not even necessary, I just added it to be clearer.

Idem with your clkpress function. Again, let's simplify. All this cleaning will have its use later.

function clkpress()
 if stat(34)==1 then
  clk=true
  p.sprite=2
 end
 if stat(34)==0 then
  clk=false
  p.sprite=0
 end
end

I'm not sure, because I never used mouse in pico8, but it looks like stat(34) is either 0 or 1. At least, you want to check wether it is 1 (then clk=true), or not 1 (then clk=false). Then you can use:

function clkpress()
 clk=(stat(34)==1)
 if clk then
  p.sprite=2
 else
  p.sprite=0
 end
end

(added) Even simpler :

function clkpress()
 clk=(stat(34)==1)
 p.sprite=0
 if(clk) p.sprite=2
end

Because a "if" test just checks if an expression is true or false. Whatever complex this expression is, it always can be resolved to a single boolean. And as you can set a boolean to a variable, nothing prevents you to directly set it with an expression.

Now get back to the hidden part of my 1st reply ("show" button), and check both your now simplified functions. First use clkpress to set a variable that will memorize clk value before it's changed. Second, modify that rather useless clkattack function so that it returns true only if old clk is false and new clk is true. No need for "if" tests, as you see you can directly return the result of an expression.

P#39583 2017-04-12 17:37 ( Edited 2017-04-13 06:18)

A thousand thanks ELGregos for the comprehensive guide, I'm so spoiled that I feel bad as I can't implement your help.

I've streamlined the code with what I agree was unnecessary in the clkattack function and moving the conditional to the attack function.

Somehow, using oldc and newc didn't make a difference, I'm missing the switch somewhere and tried to implement jclermont's tip in the game's thread.

I know I'm not using newc and oldc efficiently, any other clue would be awesome.

Thanks again for your help and patience ;)

K.

P#39594 2017-04-13 05:23 ( Edited 2017-04-13 09:23)

There's also another, if not better and simpler, solution. It only needs one variable, say, clk. Initialize clk with 0. Then:

  • increment clk when (and as long as) the mouse button is pressed. Bonus point for not allowing clk to go above 2, as you don't need upper values (plus, there's an overflow over 32768. Ok, that's 18 minutes of mouse pressing at 30 fps, but anyway).
  • otherwise (button released), set clk to 0

That can be done in your clkpress function (get rid of the rest).

Then in your attack function, just check whether clk == 1. If it is, you got your single click. If it's not, the button either is not pressed (clk==0), or has been pressed too long (clk>1).
It's easier, you should be able to make it on your own. Don't forget to first set clk to 0 in _init, otherwise you'll try to increment nil, which is not a good idea.

If not, here's the code for the previous method.

function clkpress()
 oldclk=clk
 clk=(stat(34)==1)
 p.sprite=0
 if(clk) p.sprite=2
end

function clkattack()
 return (not oldclk and clk)
end

In clkpress() I just added the 1st line, to remember how clk was before I reset it. Remember what we tried to achieve? We want the action to run when the mouse is pressed just after it was not. So we have to remember how was clk before we redefine it. Hence oldclk=clk before we reset clk.

You'd also better add this in your _init :

clk=false

If not, the first time we go in clkpress, clk=nil, then oldclk=nil, which is not a boolean and may cause bugs as nil is neither true nor false.
In clkattack, remember the shortened syntax for checking booleans? That return line is the same than

return (oldclk!=true and clk==true)

If you can't make the simpler 2nd method and want it, just ask and I'll add it. But the real matter is not to have things done, it's about knowing what you want, and how to make it.

Have fun, and think right!

P#39596 2017-04-13 07:23 ( Edited 2017-04-13 11:36)

Man, I'm almost there! >:D

I've tried both versions and they work for the exception that the HP is decremented by 2.

It's not a huge deal breaker though, but I'm wondering why in both versions it does that. I thought it could have to do with the frame rate so I tried with _update60() but it didn't make a difference. Any clue ?

Will probably play with HP values to make up for the double increment.

I've updated the cart with the simpler version to see by yourself, it's quite satisfying to be honest.

While I used ways (max, mid, click<2, for i=1,2 do, etc.) to lock the click to max of 2, it would break the function, so in the meantime I'll let it slide.

A million thanks again for your help ElGregos, I've learned so much with this thread.

I'll keep iterating with the "simpler" version since the result is the same and definitely more economical.

Cheers.

K.

P#39599 2017-04-13 09:08 ( Edited 2017-04-13 13:08)

I know it's a bit long, but it's fully functional.

Pop this in to your project and get button values from mouse.lmbp, mouse.lmb, mouse.lmbr, etc.
Turn if off and on with mouse.enabled
Put mouse:init in _init function and mouse:update in _update function

mouse={
    enabled=true,
    x=0,
    y=0,
    --mouse internal (not to be used)
    lmbwait=false,
    mmbwait=false,
    rmbwait=false,
    --mouse press
    lmbp=false,
    mmbp=false,
    rmbp=false,
    --mouse down
    lmb=false,
    mmb=false,
    rmb=false,
    --mouse release
    lmbr=false,
    mmbr=false,
    rmbr=false,
    bttn=function(self,index)
        if (not self.enabled) return false
        local mousestate=stat(34)
        if (index==0) then
            --lmb
            return band(mousestate,1)==1
        elseif (index==1) then
            --mmb
            return band(mousestate,4)==4
        else
            --rmb
            return band(mousestate,2)==2
        end
    end,--bttn()
    init=function(self)
        if (self.enabled) then
            poke(0x5f2d,1)
        else
            poke(0x5f2d,0)
        end
    end,
    update=function(self)
        self.x=stat(32)
        self.y=stat(33)
        self.lmb=self:bttn(0)
        self.mmb=self:bttn(1)
        self.rmb=self:bttn(2)
        if (self.lmb) then
            if (self.lmbr) then
                self.lmbr=false
            end
            if (not self.lmbp) then
                if (not self.lmbwait) then
                    self.lmbp=true
                    self.lmbwait=true
                end--if(not lmbwait)
            else--if(not lmbp)
                self.lmbp=false
            end--if(not lmbp)
        else--if(lmb)
            if (self.lmbp) then
                self.lmbp=false
            end
            if (not self.lmbr) then
                if (self.lmbwait) then
                    self.lmbr=true
                    self.lmbwait=false
                end
            else--if(not lmbr)
                self.lmbr=false
            end
        end--if(lmb)

        if (self.mmb) then
            if (self.mmbr) then
                self.mmbr=false
            end
            if (not self.mmbp) then
                if (not self.mmbwait) then
                    self.mmbp=true
                    self.mmbwait=true
                end--if(not mmbwait)
            else--if(not mmbp)
                self.mmbp=false
            end--if(not mmbp)
        else--if(mmb)
            if (self.mmbp) then
                self.mmbp=false
            end
            if (not self.mmbr) then
                if (self.mmbwait) then
                    self.mmbr=true
                    self.mmbwait=false
                end
            else--if(not mmbr)
                self.mmbr=false
            end
        end--if(mmb)

        if (self.rmb) then
            if (self.rmbr) then
                self.rmbr=false
            end
            if (not self.rmbp) then
                if (not self.rmbwait) then
                    self.rmbp=true
                    self.rmbwait=true
                end--if(not rmbwait)
            else--if(not rmbp)
                self.rmbp=false
            end--if(not rmbp)
        else--if(rmb)
            if (self.rmbp) then
                self.rmbp=false
            end
            if (not self.rmbr) then
                if (self.rmbwait) then
                    self.rmbr=true
                    self.rmbwait=false
                end
            else--if(not rmbr)
                self.rmbr=false
            end
        end--if(rmb)
    end--update
}

Here's a quick example for the left mouse button. You can do the same
for middle and right mouse button.

if (mouse.lmbp) print("Left mouse button was pressed")
if (mouse.lmb) print("Left mouse button is being held")
if (mouse.lmbr) print("Left mouse button released")
P#39602 2017-04-13 10:57 ( Edited 2017-04-13 15:03)

Hi Hippyman, thanks a lot for the advice, I actually tested your code and have the exact same results as before (edit. as it currently works in my last version), I believe I have an issue with frame rate as each click still decrements by 2 rather than 1.

I only had to change the first line to make it work :

   if (check_coll(a,b)==true and mouse.lmbp) then 
    rat.hp-=1
    if (rat.hp<=0) then 
     del(actors,b)

I'll have to figure out what goes wrong with the framerate or just stick with it ;)

P#39605 2017-04-13 11:51 ( Edited 2017-04-13 16:36)

[Please log in to post a comment]