Monday, November 3, 2014

Sunday, November 2, 2014

Pygame Virtual Controller Update

I worked with my son for about 2 hours today on the Pygame virtual controller for Android.   The main challenge with the controller is the use of sine, cosine, and tangent.  Although we all learn trigonometry in school, how often do you use it?  Outside of making games, I never use it.

Another challenge is getting comfortable with sprites and sprite groups for the bullets.  Since the bullets are simple, we could easily make the game without sprites.  It's possible to use rectangles stored in lists.  Sprites have a number of advantages over rectangles.  I like to use sprites because its a concise way to organize all the bullets into a single sprite group and then use bullet_group.update() and bullet_group.draw() to manage all the bullets on the screen.

The first time you type in a sprite class, it looks a bit odd.  I think the oddness of the line pygame.sprite.Sprite.__init__(self) makes the sprite more intimidating than it really is.



class Bullet(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((6,6))
        self.rect = self.image.get_rect()



After getting the bullets to fire properly with sprite groups, the next challenge was to get the player to move around the screen with a secondary virtual controller.  Although we built the code to calculate the angle of the controller for firing in the previous lesson, the player wasn't moving.  Once the player starts moving, the angle needs to be calculated from the center point of the player.  The modification to the code is minimal, but the conceptual leap of thinking of the opposite, adjacent and hypotenuse sides can be daunting when the triangle is moving all around the screen.  

Once you get the angle and the center, the code to move the player is straightforward.

def move(angle, center):
    hypotenuse = 10.0
    adjacent = math.cos(angle) * hypotenuse
    x = int(adjacent + center[0])
    opposite = math.sin(angle) * hypotenuse
    y = int(center[1] - opposite)
    return ((x, y))
At the end of the lesson, he had a working app with 360 degree firing and movement.

The next step is to get this working on his accelerometer game.  We're bumping up into the limitations of single-point touch and are trying to use the accelerometer for movement.  It's easy to access the Android accelerometer, but it's uncertain how playable the game will be.  We're using Cube Runner as a model for playability.


Saturday, November 1, 2014

Dart and StageXL Versus Python and Pygame for Teaching Children

I've used Python, Pygame, and pgs4a for several years.  I've been using Dart and StageXL for less than a month.  So far, I like Dart more than Javascript, Ruby, or Java.  The combination of Dart and StageXL is more friendly than Kivy.

Python and Pygame are completely different from Dart and StageXL.  This is okay with me as I'm focused on teaching children to program.  I'm not concerned about the end product.  The main criteria is what is a good language to teach programming concepts and what will keep their interest.

With this criteria in mind, I'll give my opinion.  Python and Pygame is the easiest path.  As proof of how easy it is to learn, my 9 year daughter can create games with Pygame using the PyCharm IDE and starting with a blank screen.  This is not unusual.  She's also learning Python at school in the 4th grade.  However, she's focused on turtle, not Pygame at school.   At home, she uses Pygame.  She can get through the lessons thanks to the awesome code completion of PyCharm.

My son can build complex apps on the Android phone with Python, Pygame and pgs4a.  He's actually pushing some of the limits of this stack and encountering known bugs.  I don't want to list all the bugs with pgs4a on Android, but from looking at StackOverflow and the questions I get by email, I know that multiple people are having problem with the sound mixer causing slowdown of the main while loop in some circumstances.  There are screen resizing problems on the Moto-G.  The lack of multi-point touch is causing a lot of usability problems for many people.

Although we looked at Kivy to solve some of these problems, I also evaluated Dart as a teaching alternative.  So far, I like it quite a bit.   This StageXL cookbook is quite fun.  Dart also has these cool Polymer.dart and AngularDart pieces.  There's info to get the Dart app running on Android as a web app.  I'm sure all of these will get better.

I'm planning to move to Dart as the basis for future curriculum for my son.  There's some downsides compared to Python.
  • The Dart Editor is pretty cool, but it doesn't do split-screen.  I can't view the same file in two windows at the same time.
  • PyCharm Pro can handle Dart, but it's not as smooth as the Dart Editor
  • The debug info of the Dart Editor is confusing
  • There's less Dart documentation geared for children.   There's a ton of Python information designed specifically for kids
  • Python and Pygame is easier.  
    • You can run everything in a single block of code without any functions or classes.  You can then go back and organize the code into classes when the kid gets it running.
    • You've got to deal with HTML, CSS in addition to Dart
  • The student may spend more of their time with HTML and CSS instead of learning programming concepts.  Tweaking the visual design of the app with HTML and CSS is more accessible and more rewarding than dealing with lists, parsing, and classes.   Designing the interface is not the purpose of these lessons.  The goal is to learn about data structures, classes, methods, functions, types.
  • Using the Python console or iPython is pretty awesome.  
Although I've been going fairly light on design, I think it's time to incorporate more design elements into his games.

There are many advantages to Dart:

  • The optional typing is really nice to isolate errors, especially for teaching purposes.
  • It returns a floating point if you do something like 1/3.  Python 2.7 will return 0.  Python 3.4 will return 0.33333, which is what you expect.  pgs4a will only work with Python 2.7.
  • Dart can be used on the server and the browser.  It also feels natural to do this.
  • Building Python strings with "string_here {}".format(var)  isn't as nice as Dart's "string_here$var"
  • Dart has this quick little "assert" statement to check for errors.
  • The graphics and UI components are pretty awesome on Dart.  With Pygame/pgsa, the only GUI toolkit I got to work was SGC and it was still a bit funky with things like text input on the phone.  My son was starting to waste a lot of time building his own button widgets.   Pygame is really designed for games.  It's not that great with the buttons, menus, text.  It's usable, but I think my son is ready for more UI work
  • The huge advantage to Dart is the distribution mechanism.  The Android apk file produced by pgs4a is big.  While it can be put into the Google Play store, it's a bit of a hassle, so much so that he's never put it into Google Play.  Also, his friends can't play the game on their iPhone, which is still in use by about half the teenagers.  He's still at the stage of only sharing games with friends and family, but I'm hoping that a web app will make it easier.


Fun and fast little exercises.






import 'dart:html' as html;
import 'package:stagexl/stagexl.dart';
import 'dart:math';

void main() {
  makeCanvas("4");
  html.querySelector("#button").onClick.listen(grabSize);
}

void makeCanvas(var radius){
  var canvas = html.querySelector('#stage');
  var stage = new Stage(canvas);
  var renderLoop = new RenderLoop();
  renderLoop.addStage(stage);

  List shapes = new List();
  var c_color = Color.Black;
  
  var rad = int.parse(radius);
  rad = rad * 4;
  print("the radius is $rad");

  
  for (int i = 50; i < 800; i= i + 50){
  
    for (int y = 50; y < 600; y = y +50){
      var r = new Random();
      int r_dec = r.nextInt(255);
      var r_g = new Random();
      int g_dec = r_g.nextInt(255);
      var b = new Random();
      int b_dec = b.nextInt(255);
      String a_hex_str = 255.toRadixString(16);
      String r_hex_str = r_dec.toRadixString(16);
      String g_hex_str = g_dec.toRadixString(16);
      String b_hex_str = b_dec.toRadixString(16);
      String col_hex = ('0x$a_hex_str$r_hex_str$g_hex_str$b_hex_str');
      int col = int.parse(col_hex);
      var circ = new Shape();
      circ.graphics.circle(i,  y,  rad);
      circ.graphics.fillColor(col);
      shapes.add(circ);

    }
  }
  
  for (var my_shape in shapes){
    stage.addChild(my_shape);
  }
}

void grabSize(html.MouseEvent event) {
  String the_name = (html.querySelector("#name_box") as html.InputElement).value;
  the_name = the_name.toUpperCase();
  html.querySelector("#name").text = the_name;
  String n_radius = (html.querySelector("#name").text);
  print(n_radius);
  makeCanvas(n_radius);
}