Now I’ve got it! You want to edit classes in such a way that all past & future instances of them have new members, right?
Indeed Java can’t do that! Creating a custom subclass doesn’t replace the original.
Nor does it force other places instantiating the original class to use our own “hacked” version. Even less can it upgrade already existing object instances.
1st languages that come to mind which can easily edit classes & objects on-the-fly are JavaScript & Lua.
Lua I barely know anything about it. But in JS we merely append new properties on a constructor’s prototype{} object.
After that, all object instances of that constructor immediately receive those new added properties.
Here’s an example sketch that adds a new method called zero() to the p5js’ p5.Vector class:
function setup() {
noCanvas();
const vec = p5.Vector.random3D();
print(vec);
print(`Method zero() exists in PVector: ${'zero' in vec}\n`);
p5.Vector.prototype.zero = function () {
this.x = this.y = this.z = 0;
return this;
};
vec.zero();
print(vec);
print('Method zero() exists in PVector: ' + ('zero' in vec));
}
Yes I am using Kotlin as main language for my processing projects. I really love the syntactic sugar it offers (extension methods, optional parameters, type inference …) and the null-safety, coroutines, a simpler functional interface for lists (more like LINQ from C#) and much more.
But I mainly use it for larger projects, where I need a good software architecture. You can find some of my projects here:
led-forest3 - very adaptive interactive installation
anna - based on led-forest3 but another installation (then one of my presentation)
Extension methods are a great too to polish an API which adds too much clutter to your code. For example, I use the following method a lot which gives you the security that you won’t ever forget the endDraw():
But really the most interesting part of kotlin is, that you do not use nullable types. So usually you can be sure that no variable is null. That leads to another way of how you write your code. Mostly processing uses the nullability, so sometimes you have to work around a bit.
For me kotlin is not “better” or “faster” then java, just more fun to use and in some ways helps me to write cleaner code.
Thank you @cansik for posting your code! Very useful to learn this new approach
Question: I’m trying to inherit from PGraphics3D but apparently when I call LCircle.draw() the PGraphics has not been initialized (NPE at clear()). Any ideas?
package com.hamoid
import processing.core.PApplet
import processing.core.PConstants
class Basic : PApplet() {
lateinit var layer : LCircle
companion object Factory {
fun run() {
val art = Basic()
//art.setSize(700, 500)
art.runSketch()
}
}
override fun settings() {
size(700, 500, PConstants.P3D)
}
override fun setup() {
background(70.0f, 20.0f, 200.0f)
layer = LCircle(this, 500, 500)
}
override fun draw() {
line(0.0f, 0.0f, width * 1.0f, height * 1.0f);
layer.draw()
}
}
fun main() {
Basic.run()
}
Update: the thing that was missing was a beginDraw() / endDraw() inside fun draw(). The clean syntax (without the myPG. prefix) made me forget I was inside a PGraphics.
Thanks! Yes, been keeping an eye on it. Although Processing core generally works fine with OpenJDK 11 as is. Was about to ship PraxisLIVE v4.3 with Java 11 but having some testing issues with crashes when closing windows on macOS. This is a bug in JOGL unfortunately so will still be there in Sam’s fork.
Is it even possible to initialise a valid PGraphics without using the createGraphics(width, height) method? I have never inherited from PGraphics3D, I always decorate it.
I was having some trouble getting the processing library to be picked up by Intellij so here’s what I added in the end to my build.gradle (Mac OS X example):
Could you describe the steps to use Gradle with Processing and Kotlin? Assuming you have Idea, Gradle and Processing installed, what’s next? Do you go to File > New > Gradle Kotlin JVM project? And then edit build.gradle to include the Processing related stuff as you just posted?
I’ve been using OPENRNDR for a few months and I’m really enjoying it.
Having previous experience with Processing and computer graphics in general helps.
Hi After learning more about Kotlin I’m concerned that the original example is a bit verbose so I decided to share an updated version with some changes:
No need to name companion object
Use PVector, PVector.dist instead of x, y
Use Int for colors, no need of floatArrayOf
Use destructuring declaration with circleSizeCounts map
Replace circleOverlaps() by .all {}
Improve weightedChoice:
No need for weights to sum 1.0
Accept any collection as input, not only colors
Use circle() instead of ellipse()
Updated Kotlin + Processing code
import processing.core.PApplet
import processing.core.PConstants
import processing.core.PVector
data class Circle(val radius: Float, val pos: PVector, var color: Int = 0)
fun main() {
CirclePacking.start()
}
class CirclePacking : PApplet() {
companion object {
fun start() {
var art = CirclePacking()
art.setSize(500, 500)
art.runSketch()
}
}
private val circleSizeCounts = listOf(
65f to 19,
37f to 38,
20f to 75,
7f to 150,
3f to 300
)
override fun setup() {
colorMode(PConstants.HSB, 360f, 100f, 100f)
noStroke()
background(70)
val circles = mutableListOf<Circle>()
for ((circleRadius, circleCount) in circleSizeCounts) {
for (i in 1..circleCount) {
// allow up to 1000 collisions
for (c in 0..1000) {
// generate random point
// A. do not allow circles to overlap canvas
// val pos = PVector(random(circleRadius, width -
// circleRadius), random(circleRadius, height - circleRadius))
// B. allow circles overlapping canvas
val pos = PVector(random(width * 1f), random(height * 1f))
val newCircle = Circle(circleRadius, pos)
if (circles.all { otherCircle ->
newCircle.pos.dist(otherCircle.pos) >
newCircle.radius + otherCircle.radius
}) {
// get random color
newCircle.color = weightedChoice(
listOf(
color(0f, 0f, random(90f, 100f)),
color(random(180f, 220f), 50f, 50f),
color(random(0f, 20f), 80f, 80f)
), listOf(0.6f, 0.3f, 0.1f)
)
circles.add(newCircle)
break
}
}
}
}
circles.forEach {
fill(it.color)
circle(it.pos.x, it.pos.y, it.radius * 2)
}
}
override fun draw() {
}
private fun <T> weightedChoice(coll: Collection<T>, weights: Collection<Float>): T {
if (coll.size != weights.size) {
error("weightedChoice() requires two collections with the same number of elements")
}
val rnd = random(weights.sum())
var sum = 0.0
val index = weights.indexOfFirst { sum += it; sum > rnd }
return coll.toList()[index]
}
}
I might have a look if I get a chance. Interesting with Java 14 and preview features enabled, your Circle could become.
record Circle(float radius, PVector pos, int color) {}
Not quite the same semantics - it’s immutable. You’ve also got things like List.of(...) - really interesting to see how Java itself is evolving and embracing some of these similar things now. Even better when Processing can and does!
Nice syntax and language features are one thing but imagine the power of Kotlin Multiplatform - writing the code once and creating sketches for Android, Java, JavaScript and more from it.
That would be nice indeed, but it does not exist so far (with Kotlin + creative coding) and it’s quite a big project.
Each target has different ways of dealing with disk access, different version of OPENGL, different interaction (mouse, keyboard, touch screen), different number of sensors, etc.
People need to get involved to make it happen and it needs to be maintained. OPENRNDR would probably be open for contributions in that direction, Processing, openFrameworks, Godot and others support different platforms like desktop, Android, Raspberry Pi, but to have something up-to-date across platforms is hard to achieve unless you have a few full time developers.
Not trying to discourage anyone though. The way to make it happen is to join and start contributing little by little