Log In  


Cart #28611 | 2016-09-16 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
1

Or you could read that subject line as, "No Objects For Noobers."

For those of you confused or confounded by Object-Oriented programming, you might be happy to know that PICO will also accept the standard spaghetti-code variety. That is where there are no system interrupt or timing routines.

How do I use a single tile to create a perfect black outline around a sprite that is already 8x8 pixels in size ? You'll have to look at the code to find out. :)

Based on DittoSlash's test cart.

https://www.lexaloffle.com/bbs/?tid=27630

1


Cart #28645 | 2016-09-17 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA


I couldn't resist wrapping the code with the "proper" _init() _update() _draw(). At this point it doesn't make a big difference. When you start drawing multiple layers of game and ui and especially if you ever drop to 15 fps, having draw calls spread out is asking for hassle.

The only thing that really got reordered was the input. Otherwise, the code is basically the same. (well, besides all the tweaks I list below)

changes:


Instead of using a separate sprite for outlining, I recycled the existing sprite.

Also, since the built-in map is there, I used it instead of m{}. Because map() treats sprite 0 specially, I moved the grass to sprite 2. (which worked fine since I'd freed it up in the previous change) Also I found map() felt nice since it's two-dimensional from the get-go.

Finally I ended up making trees slow you down, and made them 20% of the map because 50% was just too much slow for me. (was helped by rearranging sprites)

Mostly I did all this for fun and because I have spare time waiting for gigs of files to copy. (and in case it helps anyone with the built-in functions)

edit: [pedantic] Object oriented is classes and inheritance. This is just using the 3 built in functions to categorize/run things[/pedantic]


I like what you've done here, Tyroney !

I was afraid of resetting all the colors to black thinking it might affect the screen or cause a flicker - clearly it does not.

Interesting idea causing the player to shudder going over the flora tiles.

I hesitate to use the mapping space because I know at some point it cuts into the graphic tiles.

I'm also forgetting that any variable containing an integer value can at any point be promoted to floating point with a decimal.

In this case, X & Y. It would never have occurred to me to add .5 to make it move half speed as I already targeted it as an integer variable.

You are mentioning that object-oriented is classes and inheritance. Could you please post a SMALL example of this ?

And you are saying that perhaps _Init(), _Update(), and _Draw() are not ?

There's quite a bit I can learn from the code you've posted thus far on the reissue of my demo.


Cart #28669 | 2016-09-17 | Code ▽ | Embed ▽ | No License

If someone's real picky, what I added next isn't "object oriented", but I'm not here to discuss that.

So I tossed in some floaty things that could be pickups or something. Starting with the last bits I added which are easiest to explain:

in _init(), there's a new timer and the adding of the things to the things table:

--timer
	t=0

--floating things?	
 things={}
 for i=1,5	do
 	add(things,newthing(4,flr(rnd(15))*8,flr(rnd(15))*8) )
 end

in update, at the top the timer gets incremented and resets at 30

	t=(t+1)% 30

and later on I update the new things

		for i in all(things) do
			i:update()
		end

Super simple! Because I've got the magic going on in a new function down at the bottom: (hopefully commented sufficiently)

function newthing(s,x,y)
--[[make and return a new thing 
sprit s at x,y. i didn't know
what to call them, but they're
floaty-looking]]

	local thing={}
	thing.s=s--sprite
	thing.x=x
	thing.y=y
--[[floating effect has a list 
of offsets, a counter, and a 
random offset for when it does 
its floating]] 
	thing.floaties={[0]=-1,0,1,0}
	thing.float=flr(rnd(4))
	thing.r=flr(rnd(4)) 

	thing.update=function(this,...) 
		if (t+this.r)%5==0 then --every 5th frame
			this.float=(this.float+1)%4 --inc counter
			end--if 
		end--update	
	thing.draw=function(this,...)
--draw with y at current offset
		spr(this.s,this.x,this.y+this.floaties[this.float]) 
	end--draw

	return thing

end--newthing

note the use of (this,...) as an argument which lets these functions refer to their "parent" table with "this." (and also why they are called using colons in the update and draw code)

The best part about setting up "objects" like this, is I can have tables full of enemies, the player, pickups, bullets, all sorts of things, and run through them and do stuff in really small, clear loops. Picking what things to keep together can be a whole other ball of wax, but this is the basic starting point for dealing with piles of things and keeping it manageable.

(edit: just like the update, there's 3 new lines in _draw() that draws all the things in the thing table.)


I got to the words, "Super Simple" and then a bee crawled in my ear and started buzzing. It's not you, it's me. What you wrote is still too advanced for me to take in.

Yet - I'm seeing that this sort of coding style is a requirement to do some of the amazing things I've seen thus far, including true 3-dimensional graphics - which also have eluded me.

Particles by themselves were difficult enough for me to understand. I know I wrote one in BlitzMAX, but it was still really tricky for me to figure out.

' Rainbow Rain - an experiment and tutorial in TYPE variables and LINKED LISTS
' Jan 19-2016
Strict

Const speed=10 ' change to 1 for maximum speed
Const depth=0 ' change to higher # for more raindrops per cycle

SeedRnd MilliSecs()
SetGraphicsDriver GLMax2DDriver(),0 ' zero forces front buffer
Graphics 768,576

Type particle ' My 1st attempt at using TYPE variables !
  Field x ' x-coordinates
  Field y ' y-coordinates
  Field color$ ' TYPE variables can hold more than one type AND value !
End Type ' this type has 2-integers and one string for it

Local list:TList=CreateList() ' this is called a LINKED LIST
Local dot:particle,ilist:particle ' a type of array holding more than one value
Local r,i

Repeat ' (* MAIN *)

Cls ' clear display so no streaks are left on screen
If KeyDown(32) ' hold down SPACE to add a raindrop
  For i=0 To depth
    dot=New particle ' we are DEFINING a special type of variable now
    dot.x=Rand(-576,767) ' x-position of rain
    dot.y=0 ' unnecessary it seems as by saying NEW it is already zero
    r=Rand(0,5) ' now we add an entirely different type, not integer but STRING !
    If r=0 Then dot.color$="purple"
    If r=1 Then dot.color$="red"
    If r=2 Then dot.color$="orange"
    If r=3 Then dot.color$="yellow"
    If r=4 Then dot.color$="green"
    If r=5 Then dot.color$="blue"
    ListAddFirst list,dot ' add this data to the linked list
  Next
EndIf

SetColor 255,255,255 ' white (for our rain count)
DrawText "Rain: "+list.count(),0,0 ' show how many drops are in the air
For ilist=EachIn list ' EACHIN will work with non-numeric values, and we're looping only as many raindrops as there are
  If ilist.color$="purple" Then SetColor 255,0,255
  If ilist.color$="red" Then SetColor 255,0,0
  If ilist.color$="orange" Then SetColor 255,128,0
  If ilist.color$="yellow" Then SetColor 255,255,0
  If ilist.color$="green" Then SetColor 0,255,0
  If ilist.color$="blue" Then SetColor 0,0,255
  DrawLine ilist.x,ilist.y,ilist.x+7,ilist.y+14 ' simple streak
  ilist.x:+1 ' move rain down by 2 and across by 1
  ilist.y:+2
  If ilist.y>=576 Or ilist.x>=768 Then list.remove ilist ' if out of boundaries, remove from list
Next ' and YES this does affect the total count, it's not zeroed out, it's actually REMOVED !
' powerful business linked lists are

Delay speed ' decrease this number to slow down animation effect
glflush ' show our work
Until KeyDown(27) ' (* END OF MAIN *)

https://www.dropbox.com/s/klzukbe7op6zk7a/My%20TYPE%20Example%20%28Rainbow%20Rain%29.zip?dl=0

How would you write this for PICO, Tyroney ?


(edit: I'll try to keep this dead on with the code you pasted)

about tables:


So variables/tables in pico (which is basically lua) are really really flexible.

In that particle demo, you had to make a new Type with predefined contents, and later you declared two variables of that type, (one to fill the linked list, and another to hold values as you went through the list doing stuff.)

if you do "a={}" you've made a new table. A table is full of entries. Each entry has a key and a value. If you want to use it like a regular array (a[1] to a[5]) you can. If you want to fill it with "variables", you can. These three do the same thing:

a.color=3 
a["color"]=3 
a={"color"=3}

In fact, you can mix and match however you want. a[1] could be a number, and a.color could be another number, and a[2] could be an entire table. I know, craziness. So a table can behave like a complex Type, or a linked list, or even both at the same time.

first attempt:


So for your particle demo, you can just make a table (instead of a linked list) and start throwing particles into it. (each one being its own table with x and y and color) So like

list={}

for i=1,depth do
	local item={}
	item.x=rnd(127+64)-64
	item.y=0
	item.color=rnd(14)+1 --no black particles
	add(list,item)
end--for

the inside of the loop can be done in one line, no "item" needed

add(list,{"x"=rnd(127+64)-64,"y"=0,"color"=rnd(14)+1})

Everything changes below this line!

doing it more right:

First, move most of that for loop into a function for spitting out new particles:

function newdrop()
--makes and returns a new drop with random x,y and color
	local item={}
	item.x=rnd(127+64)-64
	item.y=0
	item.color=rnd(14)+1 --no black particles
	return item
end--newdrop

Now the code that spawns a drop - inside of _update() of course

function _update()
	if btn(5) then--pressed x?
		add(list, newdrop())
	end--pressed x

and we need to declare the list someplace, so it'll go into _init(), and I'll start pasting huge redundant blocks of code:

[b]
function _init()
	list={}
end--init

[/b]function _update()
	if btn(5) then--pressed x?
		add(list, newdrop())
	end--pressed x
[b]end--update[/b]

function newdrop()
--makes and returns a new drop with random x,y and color
	local item={}
	item.x=rnd(127+64)-64
	item.y=0
	item.color=rnd(14)+1 --no black particles
	return item
end--newdrop


next I'll put in the _draw():

function _init()
	list={}
end--init

function _update()
	if btn(5) then--pressed x?
		add(list, newdrop())
	end--pressed x
end--update
[b]
function _draw()
	cls()
	for i in all(list) do--all drops
		line(i.x, i.y, i.x+7, i.y+14, i.color)
	end--drops
end--draw
[/b]
function newdrop()
--makes and returns a new drop with random x,y and color
	local item={}
	item.x=rnd(127+64)-64
	item.y=0
	item.color=rnd(14)+1 --no black particles
	return item
end--newdrop


Here comes the movement and the culling of offscreen drops:

function _init()
	list={}
end--init

function _update()
	if btn(5) then--pressed x?
		add(list, newdrop())
	end--pressed x
[b]	for i in all(list) do --all drops
		i.x+=1
		i.y+=2
		if ((i.x>127) or (i.y>127)) del(list,i) --special 1-line style if statement
	end--drops[/b]
end--update

function _draw()
	cls()
	for i in all(list) do--all drops
		line(i.x, i.y, i.x+7, i.y+14, i.color)
	end--drops
end--draw

function newdrop()
--makes and returns a new drop with random x,y and color
	local item={}
	item.x=rnd(127+64)-64
	item.y=0
	item.color=rnd(14)+1 --no black particles
	return item
end--newdrop



Cart #28698 | 2016-09-17 | Code ▽ | Embed ▽ | No License


Ok, that should duplicate the code you pasted.

There's no delay in the my code so far. If you wanted to slow things down, one could add a timer (declare in _init(), then in update() increment it, and when timer it's big enough reset it and only then update the drops.)

edit: if I lost you at any point, say when and I can go back, add line by line comments, or whatever else might help.

edit edit:fixed x range

edit^3: if in doubt, paste code into pico to colorize comments/etc for slightly more clarity


I'm here, Tyroney. I'm reading this. Starting with the floaty things you added. It's quite a bit for me to take in !

[Q] 16-09-19 19:32
First question. Why can't I see your Tile work with this code ?

function _init()
	for i=0,16 do
		for j=0,16 do
--1/5 trees
		mset(i,j,((rnd(5)>4 and 1)or 2))
		end  
	end
 stop()

It does indeed STOP as I told it, but clicking on the MAP set shows blank. Is this correct code behavior ?
Additionally, you are going from 0 to 16, should it be 15 perhaps ?


Yup, I made the map 1 sq too big in each direction.

The map is generated at run time randomly, but not written to the cart. (when execution stops, the map is reverted to whatever it was when the cart was started) If one wanted to save it, you could save it with a cstore(), I suppose.

When I wrote this I was using the map space for ease of using the built in functions but trying to duplicate what you had started with, which was a dynamically generated background.


Hmm ... I think ZEP could change it so you can use STOP() and view what tile & map changes you have made, and of course, have a simple switch to say "Got It" and it reverts back to what you hard-coded there.

I'm still trying to figure out the floating thingies you have. That's really almost over my head.

What I've been working on recently though is the PICO Notepad. Making nice progress. I should be posting the newest working model tomorrow or Wednesday.

Having the ability to load and save 8k now is a boon, and I really thank you for sticking through with me on that tricky code.



[Please log in to post a comment]