Log In  

Cart [#12726#] | Code | 2015-08-17 | No License | Embed
9

Testing out an engine for Super Scaler games. It's still work in progress, much is needed to be worked out with how I ultimately want to handle the slices (tiled 8x8 images or custom stretches and sizes for everything?).

Currently, sorting of the layers is not in there as I'm having trouble figuring out the best way to use FOREACH().

I want to ADD and DEL from the tables that make up the sprites, and then use FOREACH() to do the scaling rather than arbitrary FOR/END loops based on a sprite limit. The idea is that if I can keep adding to the front and deleting from the back, then I don't need to sort anything (i.e. speed increase)...but I can't get it to work!

Halp? :)

P#12727 2015-08-17 02:08 ( Edited 2015-08-19 04:11)

Pretty great start!

One possibility, if you can boil the displayed sprites down to a byte or two (an array index), you could store it in the user memory area with PEEK() and POKE(). Just MEMCPY() the array back and poke to the front to push. Edit: That doesn't gain you much though, might as well just use a lua array like a circular buffer.

P#12731 2015-08-17 05:13 ( Edited 2015-08-17 09:55)
:: impbox

this looks awesome!! :3

you could use a circular buffer.
https://en.wikipedia.org/wiki/Circular_buffer
That's what I use for the car trails in picoracer.
Fixed size and I just keep adding to it and it'll overwrite the oldest entry.

P#12732 2015-08-17 07:00 ( Edited 2015-08-17 11:00)

Oh nice! I was hoping someone was gonna tackle this flavor of engine.

P#12733 2015-08-17 09:04 ( Edited 2015-08-17 13:04)

I'm actually super frustrated right now with trying to find documentation on the use of FOREACH.

It's seriously infuriating. Demos work. Then I put in my own code, suddenly values go missing.

Here's example of demo code and then my tiny edit that doesn't do anything except spit out an error which for the life of me I cannot figure out (because I'm not a LUA guy and the documentation for Pico-8 isn't directed at morons like me)

FUNCTION _INIT()
 SIZE={1,2,3}
END

FUNCTION _UPDATE()
 FOREACH(SIZE,SHOWEM)
END

FUNCTION SHOWEM(STUFF)
 PRINT(STUFF)
END

THAT will work.

Now if I do this:

FUNCTION _INIT()
 SIZE={1,2,3}
END

FUNCTION _UPDATE()
 FOREACH(SIZE,SHOWEM)
END

FUNCTION SHOWEM(STUFF)
 SIZE[STUFF]+=1
END

This doesn't work. It doesn't store the value back into the index of the table called.

WHY?!

This is pissing me off to no end because there's seemingly no answer to this question in the Pico-8 docs. My friend was able to do all kinds of shit with FOREACH(). However, every time I call it, no matter how simple the task, Pico8 poops on my efforts and won't give me an error message that isn't just a slap in the face with generic "We didn't do your math and we are just going to say your variable blah blah something because if we actually gave you real information, you wouldn't come to the forum...LOVE, ZEP." Okay, well, most of that error message doesn't come up, but it does indeed error out and I don't understand at all why...

As I understand it, FOREACH( collection, function()) will run the called function on every item in the collection...so WHY does it not accept my function to add 1 to all of the items in the collection?

I'm angry for sure. This is one of those things where I can't see something obvious, I know it's obvious and because of my non-LUA experience, I dunno what I'm looking for (despite the fact I'm not new to programming/scripting at all).

Someone please help. Thanks. It's getting frustrating thinking that I understand it and code rejection is saying otherwise.

P#12737 2015-08-17 13:29 ( Edited 2015-08-17 17:40)

In my experience, editing a collection with a foreach loop that's running on it causes bugged out weirdness. Try a for loop instead, maybe?

P#12738 2015-08-17 13:39 ( Edited 2015-08-17 17:39)

I had FOR in there already, but it's inefficient I think and it seems like FOREACH is already set up to be a FOR loop specifically designed to do math on a table...that's why it's so...frustrating.

P#12739 2015-08-17 13:42 ( Edited 2015-08-17 17:42)

Oof, I am sort of stumbling toward an explanation of this because I've made myself a little dizzy trying to sort through it, but, so, yes, hopefully this coheres:

Your foreach() is equivalent to

for s in all(size) do
showem(s)
end

What all() does is iterate over size and put the value of each item in size into s. You then call showem(s), in which you pass the value of a given item in the size array to a function.

That function then uses the value of an array item to index the array. And then we've got a problem, because the array's only got values indexed at [1], [2], and [3]. On your first pass, the values at those indices happen to also be the indices themselves, but that's a coincidence.

So when you call showem(1) where 1 happens to be the value of the item at size[1], you then increment the value of size[1]. Ditto for [2] and [3]. You come out with an array that looks like this: {2,3,4}. Which is what you expected.

But: then on the next pass through _update(), you call showem(2), showem(3), and showem(4). Which increments the values at size[2], size[3], and, oops, size[4]. And also size[1] has been left out of this entirely. And so you end up with size=={2,4,5,???}, depending on how PICO 8 handles indexing a nil element. (For me in testing right now it does so by crashing when it tries to do size[4].)

So, obvious problem but in subtle wrapping because your starting conditions of size={1,2,3} masks the fact that you're trying to treat (initially identical) values as indices.

P#12740 2015-08-17 13:56 ( Edited 2015-08-17 17:56)

Sorry, I misunderstood what you were trying to do x) Thought you were adding to the collection. Like add(size, stuff).
Ignore what I just said.

My assumption with the actual problem is the indexing is weird. What does print(size[stuff] += 1) say?

ed: Ninja'd with an answer! Just ignore me x)

P#12741 2015-08-17 13:58 ( Edited 2015-08-17 17:59)

Folks have mentioned a couple times missing out on the pairs() function native to Lua, which zep may or may not be planning to support, but it's more what you're hoping for here: it returns both key AND value, rather than just value, for each item in the array in question.

Right now, if you want to iterate over indexes numerically I think you may be stuck just doing a traditional for loop.

P#12742 2015-08-17 13:58 ( Edited 2015-08-17 17:58)

I mean, here's a weird little hack for using foreach to do numerical indexing into the source array using only the values produced by foreach()/all(), if for some reason that was specifically valuable, but for cases where you're literally using a list that's entirely elements indexed 1..n I'm guess this would not be an improvement over a simple for loop.

_f = 0
soze = {}

function _init()
soze={ {id=1,v=1},
       {id=2,v=2},
       {id=3,v=3} }
end

function _update()
 _f += 1
 if(_f%30==0) foreach(soze,showem)
end

function do_input()
 return(btnp(3))
end

function _draw() end

function showem(stuff)
 if(soze[stuff.id] != nil) then
  soze[stuff.id].v+=1
  print(soze[stuff.id].v)
 end
end
P#12744 2015-08-17 14:13 ( Edited 2015-08-17 18:13)

Can you give a solid example of some pseudo code to do this?

Basically I'm just trying to perform math on a table all at once, same math for each value in it...

My guesses have so far kinda failed in making more 'LUA' style code (I'm from the BASIC/VB/QBASIC school of programming mostly) so I guess if someone can help me correct the psuedocode here, that would help a lot...from my expectations, this is what I feel should work (and doesn't):

FUNCTION _INIT()
 TABLE={}
 MAX_TABLE_SIZE=20
 CURRENT_TABLE_SIZE=0
END

FUNCTION _UPDATE()
 IF (COUNT(TABLE)) < MAX_TABLE_SIZE THEN ADD_TO_TABLE()
 IF SPECIAL_EVENT=TRUE THEN DELETE_FROM_TABLE()
 FOR X = 0,(COUNT(TABLE)) DO
  MANIPULATE_TABLE(X)
 END
END

FUNCTION MANIPULATE_TABLE(PASSED_VALUE)
 LOCAL LOCAL_VALUE=RND(100)
 TABLE[PASSED_VALUE]+=LOCAL_VALUE
 CURSOR(0,X*PASSED_VALUE)
 PRINT(TABLE[PASSED_VALUE])
END

Is there something I'm missing?

EDIT: And I want to store the math done on each table value stored back in the table...and the table can change size at any second. Yeah..that's what I'm trying to do i think...lol

P#12745 2015-08-17 14:14 ( Edited 2015-08-17 18:22)

Also, I found the words NEXT and RETURN, which in BASIC FOR/NEXT go together (in Pico8 it's FOR/END?) so what does that make NEXT do and also RETURN would return a value back from a function, but it doesn't seem to work as expected. Is this command changed for Lua to mean something else?

P#12746 2015-08-17 14:38 ( Edited 2015-08-17 18:38)

That's very nearly functional as is; here's a minimally modified non-pseudocode version that'll run as is on its own:

function _init()
  table={}
  max_table_size=20
  current_table_size=0
end

function _update()
  cls()
  if (count(table)) < max_table_size then 
    add(table,1)
  end
  if special_event==true then 
    delete_from_table()
  end
  for x = 1,(count(table)) do
    manipulate_table(x)
  end
end

function manipulate_table(passed_value)
  local local_value=rnd(100)
  table[passed_value]+=local_value
  cursor(0,6*passed_value)
  print(table[passed_value])
end

function _draw() end

Changes:

  1. replaced the psuedocall to add_to_table() with an actual add(table,1)
  2. changed the initial index for x to 1, from 0; lua (and so PICO 8) defaults to arrays indexed from 1 and not 0, which fucks lots of people up in all sorts of ways. I realize this was just example code and your intent was clear, just noting it.
  3. replaced the X in that cursor() call with a 6; X isn't in scope inside the manipulate_table() call. I'm assuming the goal was to put legible space between print()ed lines.
  4. Threw a cls() into the loop for legibility.
  5. Expanded a couple of IF THEN one-liners for readability.
  6. Fixed a = vs == error in the (otherwise not used here) special_event comparison.

Core idea seems right, in other words; just make sure you're indexing from 1 in your for loop and that you're not trying to reference out-of-scope variables.

P#12747 2015-08-17 14:41 ( Edited 2015-08-17 18:41)

Thanks, I'll copy/pasta this and take a look at it...it's easier for me to have code that works to break then work from broken pieces and trying to figure out how it works! :)

P#12748 2015-08-17 14:44 ( Edited 2015-08-17 18:44)

Direct comparisons of flow control keywords from one language to the next are a recipe for heartbreak; as much as all programming languages do pretty much the same kinds of things there, there's a tremendous amount of often arbitrary inconsistency in how those things are labeled.

This is probably best as a "go look at a Lua reference" thing, as much as that's not a super satisfying answer. But there's probably several good Chapter 1 type writeups of how Lua does flow control if you want to google up something to supplement what's in the PICO 8 manual.

P#12749 2015-08-17 14:55 ( Edited 2015-08-17 18:55)

Did Zeb not say recently that certain functions, such as ADD(), DEL() and FOREACH() were a work-in-progress?

P#12753 2015-08-17 21:23 ( Edited 2015-08-18 01:23)
1

@hseiken: I just wanted to help a bit with this and add some new information, because lua tables are weird.

Basically, the {} tables are trying to be everything. Objects, lists, dictionaries, and because of this there's some weird syntax. When you create a list like this:
list = {1,2,3}

What you are actually creating is an object with three variables, starting at index 1 by default and increasing (not at 0 like a respectable language...). So calling list[1] is saying "get the first entry in this list and return the value", and is equivalent to list.[1].

But wait, what is list.[1], you ask? Well the list is actually just an object that looks like this:
list = {[1]=1,[2]=2,[3]=3}

That is syntactically correct lua code, and creates an object with three variables stored at number-type indices. Similarly, when you call list.x, it returns the value at the string "x" key, so list.x is the same as list.["x"].

And you can create objects by saying:
obj = {["x"]=1,["y"]=2} etc etc

About the sorting problem, I'd say foreach and for are the wrong way to go about it. The circular queue will only work if you know the maximum number of objects beforehand. I would do it this way:

list = {["min"]=0,["max"]=0}
function ladd(s) list.max+=1 list[list.max]=s end
function ldel(s) del(list,s) while(list.min<list.max and not list[list.min]) do list.min+=1 end end
function ldraw() local s for i=list.min,list.max do s=list[i] if(s) then spr(s.n,s.x,s.y) end end end

This will fail after 32767 sprites, but there are ways to fix the overflow if that's an issue.

P#12783 2015-08-18 23:55 ( Edited 2015-08-20 03:32)
:: impbox

yeah for the circular buffer you set a fixed size.

a double ended queue is more difficult without lua's table.remove since you'll need to renumber all the items, but it's doable.

a = {1,2,3,4,5,6,7,8,9,10}

function del_by_i(a,i)
local ret = a[i]
a[i] = nil
for i=i,#a do
a[i] = a[i+1]
end
return ret -- in case you want to use it like pop
end

del_by_i(a,5)

for i=1,#a do
print(i,a[i])
end

P#12784 2015-08-19 00:11 ( Edited 2015-08-19 04:11)

[Please log in to post a comment]

About | Contact | Updates | Terms of Use
Follow Lexaloffle:        
Generated 2019-11-21 14:50 | 0.030s | 4194k | Q:57