Log In  

Cart #19886 | 2016-04-18 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
6

Hi,
With PICO-8 0.1.6, you can now programming using OOP design. This sample use setmetatable to build a constructor.
Regards,
jihem

P#19887 2016-04-18 13:04 ( Edited 2016-05-28 04:45)

I was anxious to also try out the OOP concept because of the addition of metatable and got it working. I wanted to post my test cart but stumbled upon your post which was actually the same as what i did ^_^

Cheers!

P#19893 2016-04-18 14:50 ( Edited 2016-04-18 18:50)

any of you want to write up a simple tutorial on what this is and how to use it? i am pretty new to programming!

P#19917 2016-04-19 06:07 ( Edited 2016-04-19 10:07)

Is there any plans of supporting multiple files?

P#19918 2016-04-19 06:16 ( Edited 2016-04-19 10:16)

> any of you want to write up a simple tutorial on what this is and how to use it
I will publish notes soon.

> Is there any plans of supporting multiple files?
I don't think so (no in the spirit).

P#19945 2016-04-21 06:32 ( Edited 2016-04-21 10:32)

"> Is there any plans of supporting multiple files?
I don't think so (no in the spirit)."

I don't know about that. Have you seen the source code for games going as far back as the Atari 800 (1979)? Preppie source - consists of ~20 source code files. Many of the old 8-bit consoles were the same way. Unfortunately, there aren't a lot of games that were commercially released in the 8-bit era that have had their source code published, and of the ones that have, most of them are just disassemblies, not the original source (disassembling a binary will just spit everything out to a single file).

But yeah, most games even back then consisted of more than 1 source code file which was then compiled into a single binary, so I'm not sure how it would go against the spirit of Pico-8 to at least allow for a few pages of source code. Unless we're talking about having games that consist of multiple "disks" so that they can be bigger, but I'd question if even that would go against the spirit of the console (I mean, I guess the 8 and 16-bit consoles didn't have games that were multiple cartridges in size, so it could be argued that it wouldn't be "realistic" I suppose).

P#19946 2016-04-21 08:36 ( Edited 2016-04-21 12:41)

Or even just 3 or 4 tabs in the editor that would let you view multiple places in the same file. Currently, switching back and forth between 3 spots in a 1000 line file is a real pain in the dick, especially with the gigantic font and no scroll bar. I don't want to do that hacky shit of opening that cart in an exterior editor.

P#19948 2016-04-21 11:18 ( Edited 2016-04-21 15:18)

I can't speak for zep directly but he has said he's considering the tabs idea.

Combining tabs with a Splore-like snippet explorer: explore a BBS-hosted library of open sourced code snippets and copy them into a tab of the current project. Tons of potential in this area, and it's still compatible with the cart size limit as a forcing function for welcoming beginners and encouraging creativity.

I'm personally interested in cross-compilers because of how it was used in the 8-bit era. (picotool is intended as a foundation.) But I'd be sad if many of those benefits were baked into Pico-8 itself. I'd rather Pico-8 be easy to use than try to be its own professional dev environment. I would enjoy some external hooks into the runtime environment for third-party dev tools, but I'm not holding my breath. :)

Since it was mentioned: storing a game across multiple carts is basically possible today, not accounting for the web player. I wonder if Splore could play a role here too someday: the cart loading commands could take BBS cart IDs instead of filenames.

P#19953 2016-04-21 14:05 ( Edited 2016-04-21 18:05)

@Scathe it wouldn't be very "realistic" to use multiple cartridges, but there was some discussion about how the PICO-8 has more CPU power and less memory compared to a real computer. Something with this much power would definitely have had the space for larger games, but PICO-8 games are meant to be tiny.

If you really wanted to, you could make multiple carts with a password system that forces you to beat them in order.

P#19954 2016-04-21 14:12 ( Edited 2016-04-21 18:14)

SETMETATABLE t, mt
Each table may have an associated table called metatable (mt). The fields of the metatable are used to supplement those in the table. The __index key indicates on which table the search continues when a desired key is not found in the table (t).

In this context, the keys of a table :
• with a value are called properties (t["name "] = value)
• associated with a function are called methods (FUNCTION t:name(…) … END)

PIXEL={} –- create an empty table named PIXEL
FUNCTION PIXEL:NEW(O) -- declare the method NEW of PIXEL
  O=O OR {}
  O.X=O.X OR 0
  O.Y=O.Y OR 0
  O.C=O.C OR 7
  SETMETATABLE(O,SELF)
  SELF.__INDEX=SELF
  RETURN O
END

The PIXEL table includes the key "NEW" which is associated with the function/method PIXEL:NEW. It accepts a table as parameter : O. If this parameter is not specified , O value is nil. The boolean state of nil is false. When O is not specified in the call, the first line of the function "O=O OR {}" affects an empty table ({}) to O. The same principle applie to the X, Y and C keys to assign default values : 0, 0 and 7. The SETMETATABLE instruction and the assignment to SELF.__INDEX associate PIXEL metatable to the O table (at this point O has "all the skills" of PIXEL including the DRAW method).

FUNCTION PIXEL:DRAW() – DRAW method
  COLOR(SELF.C)
  PRINT(SELF.X..","..SELF.Y.."=>"..SELF.C)
  PSET(SELF.X,SELF.Y)
END

Inside a method (i.g. PIXEL:NEW, PIXEL :DRAW), SELF is a reference to host table method.

CLS()
CURSOR(0,64)
P0=PIXEL:NEW() -- P0 est un PIXEL (par défaut X=0,Y=0,C=7)
P1=PIXEL:NEW({X=10,Y=10,C=11}) -- P1 est un PIXEL (X=10,Y=10,C=11)
P0:DRAW() -- dessin P0
P1:DRAW() -- dessin P1

The creation and display of P0 and P1 pixels illustrate the benefits of this approach (object). When created, you can specify all or part of their characteristics (properties) with the use of a single function (method). The display method (DRAW) does not need to be declared for each pixel : it’s shared.
To draw a parallel with other languages (C ++ , C #, Java , ...) :
• The NEW method is a constructor.
• The metatable PIXEL is a class.
• The tables P0 and P1 are objects (instances of PIXEL class).
The methods can also adopt various behaviors depending on the type of arguments passed as parameters (see TYPE) <=> polymorphic methods.
The main advantage of this approach ( OOP ) is to allow the creation of levels of abstraction. Example: separate containers ( linked lists , dictionary, ... ) from content (integers, strings , tables ... ) to pool treatment inherent to the container (create, add, delete, search , ...) whatever content. The subject is vast and led to the design patterns.

In the hope, this will help, have a nice day.
jihem


If you speak french, get involved in the http://picoscope2016.fr
If you don't speak french, it doesn't matter. We speak pico8 and english too.
Register !!! If not, you will miss the event and your friends...

P#19962 2016-04-22 06:25 ( Edited 2016-04-22 10:25)

@Connorses: In the home computer space, games used multiple disks quite frequently. And that's not considering things like Wizardry or later Baldur's Gate with their character imports. Early releases of Wizardry 2 and 3 actually required importing a character!

I believe the Famicom Wizardry ports supported it using a special peripheral, but it's true that it's not that common on the console side, at least until memory cards came about. I can only think of Sonic 3 & Knuckles that actually used multiple cartridges.

P#20051 2016-04-29 02:26 ( Edited 2016-04-29 06:29)

great news on the constructor jihem. I didn't check the update notes, but this makes me quite happy since the game I am currently working on was an attempt at object oriented design within pico8. I got methods by assigning anonymous functions to tables. However I couldnt find a way to build a constructor. so i had to make do with initialization functions. metatables will greatly improve our source code though

P#20598 2016-05-15 01:42 ( Edited 2016-05-15 05:43)

This is great stuff, although I'm gonna have to read it over these details again and also the Lua manual because this metatable stuff still gives me a headache. I've written a disgusting amount of Lua without understanding them.

P#20631 2016-05-16 00:22 ( Edited 2016-05-16 04:22)

Oh Thank you Jihem !
Very good works. Using OOP, you save my time ^^

I'm using this right in my next game. Probably for the PICO-8 Jam #2 next week.

P#20637 2016-05-16 08:12 ( Edited 2016-05-16 12:12)

I don't understand the argument about the "spirit" of pico8 where it should looks like a console from the 80s when you are speaking about OOP and no one object about, no console has been programmed using OOP until the 32bit era at best, and I doubt that the PlayStation 1 was programmed with something else as C, and all 8bit was made in assembly, most of them the 16bit (maybe some attempts to use C there, but I have no certainty there)

So OOP is clearly anachronistic :p

P#20638 2016-05-16 09:23 ( Edited 2016-05-16 13:23)

@diggin.wilson @Aslan85 You're welcome :-)

@Godzil
For me, the goal of pico-8 is to learn in an easy way the art of programming. It offers a challenging environment with its own limits. Today, most of the engineers are using C#, Java with a lot of gigabits and have forgotten how to optimize. Pico-8 is a very good platform to experiment concepts (without spending to much time doing the assets). Smalltalk first appeared in 1972 and is the precursor of Java, C++, C#. It's full object (not only oriented). I was interested in pico-8 because I can use modern knowledge in a "test tube". Then, I discover that it was more than that. It's a great artistic way of doing games. You will feel it after playing some cartridges. There is a spirit beyond pico-8. The goal is not to do games like we were in the 80s. The goal is to do art with limited capabilites using our brain.
Have a good day and do stuffs as you like it ;-)

P#20651 2016-05-16 13:07 ( Edited 2016-05-16 17:07)

My message wasn't against the use of OOP in Pico8, but about the reaction of some people about the "spirit of pico-8".

I know about the history Object Oriented Languages, and well aware of smalltalk, but smalltalk never ran on a 6502, a 8086, a 6809 or a Z80, and not even on 16bit CPU like the 65C816.

Game development and hardware have always been "late" compared to current programming practices. An exemple are threading. Threads are in use on "normal" computer programming for ages now, but has only been recently "discovered" in games, and there are still a lot of games that are mono-threaded and running a single loop.

i'm not saying it's bad, just that game development and "standard' development are two different worlds and needs.

And Smalltalk is only precursor of ObjectiveC, the C++ (and the derivatives which are Java then C#) are not descendent of Smalltalk.

So don't get me wrong, I'm not agains the use of object paradigm in Pico-8, but just I found a bit amusing to see people saying "no we must not have that because it's not in the spirit of Pico-8, and it wasn't there on the atari 2600 in 1979" where at the same time they praise OOP in Pico-8.. :)

P#20667 2016-05-16 17:58 ( Edited 2016-05-16 21:58)

Humans are paradoxical. They want change in continuity.
Sometime, I'm a mystery to myself. Especially when I talk to pico-8 while coding. Do not wait for the truth about the spirit of pico-8 from me. I have only feelings and wishes... ;-)
Have a good day

P#20683 2016-05-17 06:45 ( Edited 2016-05-17 10:45)

Hehe :)

P#20684 2016-05-17 06:48 ( Edited 2016-05-17 10:48)
2

A slight addendum to jihem's example: a better way to set default values for new instances is to set them in the prototype object:

pixel = {
  x = 0,
  y = 0,
  c = 7
}
function pixel:new(o)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  return o
end

The rest of the code behaves the same way, including support for an initializer table passed to new(). This is an improvement because you can define sub-prototypes that can override the defaults (and inherit the defaults not overridden):

newpixel = pixel:new({y=100})

p1 = pixel:new()
print(p1.x)   -- 0
print(p1.y)   -- 0

p2 = newpixel:new()
print(p2.x)   -- 0
print(p2.y)   -- 100

The "o.y=o.y or 0" construction doesn't support this because "p2 = newpixel:new()" doesn't pass in an initializer object, so the "newpixel" prototype gets overridden by the assignment of the initial value in the "pixel" prototype's new(). By setting initial values in the original prototype, sub-prototypes can override the defaults and instances will see the new defaults.

P#21527 2016-05-28 00:45 ( Edited 2016-05-28 04:45)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-19 08:59:41 | 0.063s | Q:52