Apache Cordova Error: Failed to find ‘JAVA_HOME’ environment variable. Try setting it manually.

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Hello there dear internet friend! It looks like you are having some trouble getting Apache Cordova to work. If you happen to be on a Mac, this blog post is for you! Likewise, a similar fix should work on Windows as well.

This isn’t my first time running into this quite annoying problem. Assuming you have Android Studio installed, the issue is either that Android Studio hasn’t set a global path to Java, or Android Studio is using a newer version of Java than the older version 8 that Cordova is still using.

Now if you happen to be really good with the UNIX operating system you can go track down Java and set the path yourself, or you can simply go with the easier solution that I’ve been using on all of my machines.

First, go ahead and install the brew package manager with the following terminal command:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 

Next, install cask and the OpenJDK version of Java:

$ brew tap caskroom/cask

$ brew tap AdoptOpenJDK/openjdk

$ brew cask install adoptopenjdk8

Now, we still aren’t quite done. If you try to run cordova at this point you will likely encounter a similar error related to grade:

Checking Java JDK and Android SDK versions
ANDROID_SDK_ROOT=undefined (recommended setting)
ANDROID_HOME=/Users/topher/Library/Android/sdk (DEPRECATED)
Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle
in your path, or install Android Studio

To fix this, all you have left to do is install gradle with brew:

$ brew install gradle

And that’s it! Now you can run your Cordova app on your device:

$ cordova run android --device

 

UISceneSession is only available in iOS 13.0 or newer

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Okay, so you’ve stumbled upon this terribly annoying error message: UISceneSession is only available in iOS 13.0 or newer, now what? The best answer is to simply update the software on the iPhone that you are trying to run your app.

The worse answer is to actually go in to the code by hand and add @available attributes to the parts of the boilerplate code generated by Xcode that aren’t compatible with the older version of iOS running on your test device. But in my opinion this is trying to swim against the current. Just go ahead and update the software on your phone and all will be well.

Although if I remember correctly, this is always going to be sort of a damned-if-you-update, damned-if-you-don’t-update sort of situation. You may end up finding yourself running into the opposite situation: You update the version of iOS on your iPhone, then the older version of Xcode becomes out of sync with your device. Unfortunately this is just the way of native mobile development— a never ending series of software updates.

 

How to Teach Turtle Graphics with Python

Quick little starter template for use teaching introductory python programming to students using the turtle graphics library =>

import turtle
screen = turtle.Screen()
screen.screensize()
screen.setup(width=1.0, height=1.0)
screen.addshape("sprite.gif")
sprite = turtle.Turtle()
sprite.shape("sprite.gif")
sprite.penup()
sprite.goto(0, 0)
sprite.goto(200, 200)
sprite.goto(-200, 200)
sprite.goto(-200, -200)
sprite.goto(200, -200)
sprite.goto(200, 200)
turtle.mainloop()
 

woohoo.cs

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Funny C# Winforms project/tutorial I built with one of my students. Inspired by woohooooo.com. Executable version coming soon…

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WoohooWinform
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Find File Path to Main Directory (Contains Main Program and Additional Files)
string pathToDirectory = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
// Create SoundPlayer Object Which Will Play Our WAV File
System.Media.SoundPlayer player = new System.Media.SoundPlayer();
// Tell The SoundPlayer Object Where Our WAV File is Located
player.SoundLocation = pathToDirectory + @"\woohoo.wav";
// Say Woohoo!
player.Play();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
view raw woohoo.cs hosted with ❤ by GitHub
 

Cordova Screen Orientation (Lock) Plugin Not Working

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

If you find yourself struggling to get the Apache Cordova screen orientation lock plugin to work, the problem is most likely that you are calling the .lock() method before the ‘deviceready’ event has fired. To fix this problem, simply create a call back function containing your .lock() method call, then pass this callback function as an argument to the deviceready event listener like so =>

First, make sure to install the screen orientation plugin for apache cordova

$ cordova plugin add cordova-plugin-screen-orientation

Then, rewrite your code to look something like this…

// Lock Device Orientation
function lockDeviceOrientationCallback() {
// set to either landscape
screen.orientation.lock('portrait');
console.log("locking device orientation...");
}
document.addEventListener("deviceready", lockDeviceOrientationCallback, false);
 

Pong in Python vs. Pong in JavaScript: Battle of Introductory Game Dev Tutorials

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Battle of the introductory game dev tutorials by myself and my student “Squitato” =>

# Copyright (c) 2018 Peter Kwak (Edited by Chris Pedersen)
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
import turtle
# Create Game Window
screen = turtle.Screen()
# screen.setup(500, 400)
screen.screensize(500, 500, "black")
screen.bgcolor("black")
# screen.addshape("Paddle.jpg")
# Create Ping Pong Ball
ball = turtle.Turtle()
ball.penup()
ball.speed(0)
ball.shape("circle")
ball.color("white")
# Create Left Ping Pong Paddle
paddle1 = turtle.Turtle()
paddle1.penup()
paddle1.speed(0)
paddle1.setx(-200)
paddle1.shape("square")
paddle1.shapesize(4.5, 1, 0)
paddle1.fillcolor("white")
# Create Right Ping Pong Paddle
paddle2 = turtle.Turtle()
paddle2.penup()
paddle2.speed(0)
paddle2.setx(200)
paddle2.shape("square")
paddle2.shapesize(4.5, 1, 0)
paddle2.fillcolor("white")
# Create Scoreboard
scoreWriter = turtle.Turtle()
scoreWriter.penup()
scoreWriter.speed(0)
scoreWriter.hideturtle()
scoreWriter.color("white")
# Set Ball Trajectory
rise = 3
run = 3
# Set Score
score1 = 0
score2 = 0
# Create Function Which Will Move Player 1's Paddle Up
def up1():
paddle1.sety(paddle1.ycor() + 50)
# Create Function Which Will Move Player 1's Paddle Down
def down1():
paddle1.sety(paddle1.ycor() - 50)
# Create Function Which Will Move Player 2's Paddle Up
def up2():
paddle2.sety(paddle2.ycor() + 50)
# Create Function Which Will Move Player 2's Paddle Down
def down2():
paddle2.sety(paddle2.ycor() - 50)
# Create Function To Update Scoreboard
def updateScoreboard():
global scoreWriter
global score1
global score2
global ball
scoreWriter.clear()
myFont = ("Arial", 40, "bold")
scoreWriter.goto(-100, 150)
scoreWriter.write(score1, font=myFont)
scoreWriter.goto(100, 150)
scoreWriter.write(score2, font=myFont)
ball.goto(0, 0)
# Set Event Listeners
# These event listeners will listen for button presses (up, down, etc.)
screen.onkey(up1, "w")
screen.onkey(down1, "s")
screen.onkey(up2, "Up")
screen.onkey(down2, "Down")
screen.listen()
# Create Main Game Loop (Simulates Time, Keeps Game Running)
while True:
# Move Ball
ball.goto(ball.xcor() + run, ball.ycor() + rise)
# Detect Top or Bottom Boundary Strike
# (Reverses the Ball's Direction of Travel)
if ball.ycor() > 200 or ball.ycor() < -200:
rise = -rise
# Detect Paddle Strike (Player 1)
# (Also Reverses the Ball's Direction of Travel)
if abs(paddle1.xcor() - ball.xcor()) < 15:
if abs(paddle1.ycor() - ball.ycor()) < 50:
run = -run
# Detect Paddle Strike (Player 2)
# (Also Reverses the Ball's Direction of Travel)
if abs(paddle2.xcor() - ball.xcor()) < 15:
if abs(paddle2.ycor() - ball.ycor()) < 50:
run = -run
# Detect When A Player Scores a Point
if ball.xcor() > 250:
# Increment player1's score by 1 point when his ball
# travels past the paddle of his opponent, player 2.
score1 = score1 + 1
updateScoreboard()
ball.goto(0, 0)
elif ball.xcor() < -250:
# Increment player2's score by 1 point when his ball
# travels past the paddle of his opponent, player 1.
score2 = score2 + 1
updateScoreboard()
ball.goto(0, 0)
# Christine, My Super Sweet AI Goes HERE...
if ball.ycor() > paddle2.ycor() + 25:
paddle2.sety(paddle2.ycor() + 15)
elif ball.ycor() < paddle2.ycor() - 25:
paddle2.sety(paddle2.ycor() - 15)
view raw pong.py hosted with ❤ by GitHub

NOTE: For the PongJS demo, you will need to manually install p5.play.js as it is not available via CDN =>

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
<!-- NOTE: Must Download and Install p5.play.js Manually, it is not available via CDN -->
<script src="p5.play.js"></script>
</head>
<body>
<script src="pong.js"></script>
</body>
</html>
view raw pong.html hosted with ❤ by GitHub
//pong clone
//mouse to control both paddles
var paddleA, paddleB, ball, wallTop, wallBottom;
var MAX_SPEED = 10;
function setup() {
createCanvas(800, 400);
//frameRate(6);
paddleA = createSprite(30, height/2, 10, 100);
paddleA.immovable = true;
paddleB = createSprite(width-28, height/2, 10, 100);
paddleB.immovable = true;
wallTop = createSprite(width/2, -30/2, width, 30);
wallTop.immovable = true;
wallBottom = createSprite(width/2, height+30/2, width, 30);
wallBottom.immovable = true;
ball = createSprite(width/2, height/2, 10, 10);
ball.maxSpeed = MAX_SPEED;
paddleA.shapeColor = paddleB.shapeColor =ball.shapeColor = color(255, 255, 255);
ball.setSpeed(MAX_SPEED, -180);
}
function draw() {
background(0);
paddleA.position.y = constrain(mouseY, paddleA.height/2, height-paddleA.height/2);
paddleB.position.y = constrain(mouseY, paddleA.height/2, height-paddleA.height/2);
ball.bounce(wallTop);
ball.bounce(wallBottom);
var swing;
if(ball.bounce(paddleA)) {
swing = (ball.position.y-paddleA.position.y)/3;
ball.setSpeed(MAX_SPEED, ball.getDirection()+swing);
}
if(ball.bounce(paddleB)) {
swing = (ball.position.y-paddleB.position.y)/3;
ball.setSpeed(MAX_SPEED, ball.getDirection()-swing);
}
if(ball.position.x<0) {
ball.position.x = width/2;
ball.position.y = height/2;
ball.setSpeed(MAX_SPEED, 0);
}
if(ball.position.x>width) {
ball.position.x = width/2;
ball.position.y = height/2;
ball.setSpeed(MAX_SPEED, 180);
}
drawSprites();
}
view raw pong.js hosted with ❤ by GitHub
 

ModuleNotFoundError: No module named ‘Tkinter’

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Fret not dear pythoneer, all you need to do to fix this is change Tkinter to tkinter as the name of the module has changed in Python 3. Whoops! Also, make sure to change

print "stuff"
to
print("stuff")
and all will be well!

from tkinter import *
class Application(Frame):
def say_hi(self):
print("hi there, everyone!")
def createWidgets(self):
self.QUIT = Button(self)
self.QUIT["text"] = "QUIT"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.pack({"side": "left"})
self.hi_there = Button(self)
self.hi_there["text"] = "Hello",
self.hi_there["command"] = self.say_hi
self.hi_there.pack({"side": "left"})
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
root = Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
 

Deal or no Deal? by Alex W.

My Student Alex W just finished up his first app, Deal or No Deal. If you’d like to check it out, you can download the .apk to your Android phone by clicking the SourceForge download button below. Great work Alex!

Download DealOrNoDeal

NOTE: Please make sure to enable installation of apps from unknown sources on your Android device prior to downloading.

Settings > Security > Allow installation of apps from unknown sources

 

Roblox Scripting Lesson 0

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Quick little blog post here on how to get started with scripting in Roblox Studio. These two example scripts should be added under the ServerScriptService and the variable names should match the baseplate and part added to your blank starter project =>

local basePlate = game.Workspace.Baseplate
while true do
basePlate.BrickColor = BrickColor.new(1.0, 0.08, 0.58) --hot pink
wait(0.25)
basePlate.BrickColor = BrickColor.new(0.0, 1.0, 0.0) --lime green
wait(0.25)
basePlate.BrickColor = BrickColor.new(0.0, 1.0, 1.0) --aqua
wait(0.25)
basePlate.BrickColor = BrickColor.new(0.0, 1.0, 1.0) --purple
wait(0.25)
basePlate.BrickColor = BrickColor.new(1.0, 1.0, 0.0) --yellow
end
local practicePart = game.Workspace.PracticePart
while true do
practicePart.BrickColor = BrickColor.new(1.0, 0.08, 0.58) --hot pink
wait(0.25)
practicePart.BrickColor = BrickColor.new(0.0, 1.0, 0.0) --lime green
wait(0.25)
practicePart.BrickColor = BrickColor.new(0.0, 1.0, 1.0) --aqua
wait(0.25)
practicePart.BrickColor = BrickColor.new(0.0, 1.0, 1.0) --purple
wait(0.25)
practicePart.BrickColor = BrickColor.new(1.0, 1.0, 0.0) --yellow
end
 

Hello, World Tutorial with Turbolinks by topherPedersen & jaxatax

Really simple two page tutorial on adding Turbolinks magic to your traditional webapp in order to achieve a SPA (singe page application) feel without having to learn a complicated framework like React, Angular or Vue. Simply import Turbolinks, then call Turbolinks.visit() to load your pages in the background with Turbolinks & AJAX =>

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js"></script>
<style>
body {
background-color: blue;
}
a {
color: white;
}
</style>
</head>
<body>
<button onclick="Turbolinks.visit('mylink.html');">click me</button>
</body>
</html>
view raw index.html hosted with ❤ by GitHub
view raw mylink.html hosted with ❤ by GitHub