javascriptandroidgame-engineandroid-scripting

AndroidScript DrawText() new line?


I'm working on a fully-featured, basic classic RPG (JRPG) using the Android "Javascript" IDE--AndroidScript (which is great!). Here's a few questions to start off: (I'm going to ask in separate questions to get more reputation--it's hard to get in the beginning. ha)

QUESTION: I'm creating the battle text (ie "You attack for 8.\nGoblin attacks for 2."). I'm trying to use one string and add the text, depending on who goes first,separated by a new line character. However, in canvas.DrawText(string, x, y), it doesn't seem to allow "\n", and i can't fit that much text in one line on my (thus any) phone. So it would require a lot of unnecessary condition tests without using one string with the new line character. Can one insert new line characters in an image's DrawText() method?

It's excessive, but here's all the code thus far:

/*
 * My first JavaScript RPG
 * @author I don't care...please steal this.
 */

var enemyArray = [];

function Enemy( type, level, str, hp, totalhp, x, y, speed )
{
  this.type = type; 
  this.level = level;
  this.str = str;
  this.hp = hp;
  this.totalhp = totalhp;
  this.exp = level * 3;
  this.gold = level;
  this.x = x;
  this.y = y;
  this.isAlive = true;
  this.speed = speed;
}

var STATE = {
  MAINMENU : {value: 0, name: "Main Menu", code: "M"}, 
  WORLDMAP : {value: 1, name: "World Map", code: "W"}, 
  BATTLE : {value: 2, name: "Battle", code: "B"},
  STATUS : {value: 3, name: "Status", code: "S"},
  INVENTORY : {value: 4, name: "Inventory", code: "I"},
  DEAD : {value: 5, name: "Dead", code: "D"},
};

var player = {
    yourTurn: true,
    name : "",
    x : 0.5,
    y : 0.9,
    level : 1,
    strength : 2,
    intel : 2,
    totalhp : 10,
    hp : 10,
    totalmp : 3,
    mp : 3,
    level : 1,
    exp : 0,
    gold : 0,
    inventory : [],
    speed : 0.002,
    playerSpeedMultiplier : 20 // it's low so that the run decision uses even sides
}

var game = {
    timer : null,
    isPaused : false,
    quit : false,
    state : STATE.MAINMENU,
    level : 0,
    enemies : enemyArray,
    currentEnemy : null
}

var ui =
{
    battleText : "",
    init : function(){
         //Lock screen orientation to Portrait.
        app.SetOrientation( "Portrait" );

        //Stop screen turning off.
        app.PreventScreenLock( true );

        //Create a layout with objects vertically centered.
        lay = app.CreateLayout( "linear", "Vertical,FillXY" );    
        lay.SetBackColor( "#000000" );

        //Set canvas size
        var canvasHeight = 0.75;
        var canvasWidth = 1.0;

        //Create an blank image to act as our drawing 'canvas'.
        //(For performance reasons, we limit the internal bitmap to 
        //480x800 and set screen updating to manual mode).    
        canvas = app.CreateImage( null, canvasWidth, canvasHeight, "fix", 480, 800 );
        canvas.SetAutoUpdate( false );
        lay.AddChild( canvas );

        //Create menu button.
        btnStart = app.CreateButton( "Start", 0.4 );
        btnStart.SetMargins( 0, 0.02, 0, 0 );
        btnStart.SetOnTouch( btn_start );
        lay.AddChild( btnStart );

        moveButtons = app.CreateLayout( "Linear", "Horizontal" );
        lay.AddChild( moveButtons );

        btnLeft = app.CreateButton( "Left", 0.2, 0.16 );
        btnLeft.SetOnTouch( btn_left );
        moveButtons.AddChild( btnLeft );

        layVert = app.CreateLayout( "Linear", "Vertical" );

        btnUp = app.CreateButton( "Up", 0.3, 0.08 );
        btnUp.SetOnTouch( btn_up );
        layVert.AddChild( btnUp );
        btnDown = app.CreateButton( "Down", 0.3, 0.08 );
        btnDown.SetOnTouch( btn_down );
        layVert.AddChild( btnDown );

        moveButtons.AddChild( layVert );

        btnRight = app.CreateButton( "Right", 0.2, 0.16 );
        btnRight.SetOnTouch( btn_right );
        moveButtons.AddChild( btnRight );

        btnLeft.SetVisibility( "hide" );
        btnUp.SetVisibility( "hide" );
        btnDown.SetVisibility( "hide" );
        btnRight.SetVisibility( "hide" ); 

        battleButtons = app.CreateLayout( "Linear", "Horizontal" );
        lay.AddChild( battleButtons );

        btnAttack = app.CreateButton( "Attack", 0.2, 0.16 );
        btnAttack.SetOnTouch( btn_attack );
        battleButtons.AddChild( btnAttack );

        layMid = app.CreateLayout( "Linear", "Vertical" );

        btnItem = app.CreateButton( "Item", 0.3, 0.08 );
        btnItem.SetOnTouch( btn_item );
        layMid.AddChild( btnItem );
        btnRun = app.CreateButton( "Run", 0.3, 0.08 );
        btnRun.SetOnTouch( btn_run );
        layMid.AddChild( btnRun );

        battleButtons.AddChild( layMid );

        btnMagic = app.CreateButton( "Magic", 0.2, 0.16 );
        btnMagic.SetOnTouch( btn_magic );
        battleButtons.AddChild( btnMagic );

           //Status button
          btnStatus = app.CreateButton( "Status", 0.9, 0.025, "blue" ); 
          btnStatus.SetOnTouch( btn_status ); 
          lay.AddChild( btnStatus );

        btnAttack.SetVisibility( "gone" );
        btnItem.SetVisibility( "gone" );
        btnRun.SetVisibility( "gone" );
        btnMagic.SetVisibility( "gone" );


         //Status slider
         //Create a layout we can slide over the main layout. 
         laySlide = app.CreateLayout( "Linear", "FillXY" ); 
         laySlide.SetPadding( 0, 0.1, 0, 0 );  
         laySlide.SetBackground( "/Sys/Img/GreenBack.png" ); 
         laySlide.SetVisibility( "Hide" ); 

         //Create tabs.
         var tabs = app.CreateTabs( "STATUS,EQUIP,INVENTORY", 0.8, 0.8, "VCenter" );
         tabs.SetOnChange( tabs_OnChange ); 
         laySlide.AddChild( tabs ); 

         //Create button and add to main layout. 
         btnBack = app.CreateButton( "Back", 0.3, 0.06, "gray" ); 
         btnBack.SetOnTouch( btnBack_OnTouch ); 
         laySlide.AddChild( btnBack ); 

         btnStatus.SetVisibility( "gone" );

        //Add layouts to app.    
        app.AddLayout( lay );
        app.AddLayout( laySlide );

        //Switch off debugging for max speed.
        app.SetDebugEnabled( false );
    },
    write : function(){},
    update: function(){}
}


//STATUS SLIDER
//Called when user touches our 'slide' button. 
function btn_status() 
{ 
    laySlide.Animate( "SlideFromRight" ); 
    game.isPaused = true;
} 

//Called when user touches our 'back' button. 
function btnBack_OnTouch() 
{ 
    laySlide.Animate( "SlideToLeft" );
    game.isPaused = false;     
} 

//Handle tab selection.
function tabs_OnChange( name )
{
    app.ShowPopup( name );
}



//Called when application is started.
function OnStart()
{    
    ui.init();

    //Call DrawFrame function 30x a second.
    game.timer = setInterval( drawFrame, 1000/30 ); // 30 default    
}

//Update and redraw all game graphics.
function drawFrame()
{
    //Clear the canvas.
    canvas.Clear();

    if(game.state == STATE.MAINMENU) {
        drawMenu();
    }
    if(game.state == STATE.WORLDMAP) {
        drawWorld();
        drawChar();
        drawEnemies();
        areAllEnemiesDead();
    }
    if(game.state == STATE.BATTLE) {
        drawBattleScreen();
    }
    if(game.state == STATE.STATUS) {
        drawStatusScreen();
    }
    if(game.state == STATE.INVENTORY) {
        drawInventory();
    }
    if(game.state == STATE.DEAD) {
        drawDead();
    }

    //Update the canvas.
    canvas.Update();

    //Quit game if required.
    if( game.quit ) return;
}

function goToNextLevel(){
    game.level += 1;

    player.hp = player.totalhp;
    player.mp = player.totalmp;

    app.ShowPopup( "Level " + game.level );
    btnStart.SetVisibility("gone");
    btnLeft.SetVisibility( "show" );
    btnUp.SetVisibility( "show" );
    btnDown.SetVisibility( "show" );
    btnRight.SetVisibility( "show" );
    btnAttack.SetVisibility( "gone" );
    btnItem.SetVisibility( "gone" );
    btnRun.SetVisibility( "gone" );
    btnMagic.SetVisibility( "gone" );
    canvas.SetBackColor( "#008200"  );

   for (var i = 0; i < game.enemies.length; i++) {
       game.enemies.pop();
    }
    player.x = 0.5;
    player.y = 0.9;
    createEnemies();
    game.state=STATE.WORLDMAP;
}

//Draw the Menu
function drawMenu()
{
    //Draw header
    canvas.SetTextSize( 14 );
    canvas.SetPaintColor( "#ff0088ff"  );
    canvas.DrawText( "Super Best RPG,", 0.1, 0.1 );

    //Draw info
    canvas.SetTextSize( 16 );
    canvas.SetPaintColor( "#ffff0000"  );
    canvas.DrawText( "Battle great moon", 0.1, 0.3 );
}

//Called when user presses 'Start' button.
function btn_start()
{
    goToNextLevel();
    btnStatus.SetVisibility( "show" );
}

function createEnemies(){
 app.ShowPopup( "Level " + game.level );
    for(var i = 0; i < game.level; i++) {
        game.enemies.push(
            new Enemy("Goblin", 
                                  1,
                                  Math.pow(1.2, game.level),
                                  5,
                                  game.level * 5,
                                  (Math.random() * 0.58) + 0.22,
                                  (Math.random() * 0.89),
                                  0.002
                                  )
        );
    }

}

//Called when user presses 'up'
function btn_up()
{
    if(player.y > 0.06) {
        player.y -= player.speed * player.playerSpeedMultiplier;
        app.Vibrate( "0,30" );
    }
}

//Called when user presses 'down'
function btn_down()
{
    if(player.y < 0.90) {
        player.y += player.speed * player.playerSpeedMultiplier;
        app.Vibrate( "0,30" );
    }
}

//Called when user presses 'left'
function btn_left()
{
    if(player.x > 0.23) {
        player.x -= player.speed * player.playerSpeedMultiplier;
        app.Vibrate( "0,30" );
    }
}

//Called when user presses 'right'
function btn_right()
{
    if(player.x < 0.77) {
        player.x += player.speed * player.playerSpeedMultiplier;
        app.Vibrate( "0,30" );
    }
}

//Called when user presses 'Attack'
function btn_attack()
{
    ui.battleText = "";
    if(player.speed >= game.currentEnemy.speed) {
        youAttack();
        player.yourTurn = false;
        enemyAttack();
        player.yourTurn = true;
    }
    else {
        player.yourTurn = false;
        enemyAttack();
        player.yourTurn = true;
        youAttack();
    }
}

//Called when user presses 'Item'
function btn_item()
{
    ui.battleText = "";
    if(player.yourTurn) {

    }
}

//Called when user presses 'Run'
function btn_run()
{
    ui.battleText = "";
    if(player.yourTurn) {
        if(player.speed >= game.currentEnemy.speed) {
            game.currentEnemy.isAlive = false;
            battleExit();
            game.state = STATE.WORLDMAP;
        }
        else {
            player.yourTurn = false;
            enemyAttack();
            player.yourTurn = true;
        }
    }
}

//Called when user presses 'Magic'
function btn_magic()
{
    ui.battleText = "";
    if(player.yourTurn) {

    }
}

function drawWorld() 
{
    canvas.SetPaintStyle( "Fill" ); 
    canvas.SetPaintColor( "#555500" );
    canvas.DrawRectangle(0.2, 0.0, 0.8, 1.0);   

    //HUD
    //level
    canvas.SetTextSize( 24 );
    canvas.SetPaintColor( "#ff22aaaa"  );
    canvas.DrawText( "" + game.level, 0.05, 0.1 );

    //health/magic text
    canvas.SetTextSize( 6 );
    canvas.SetPaintColor( "#ff000000"  );
    canvas.DrawText( "HP: " + player.hp + "\\" + player.totalhp, 0.01, 0.95 );
    canvas.DrawText( "MP: " + player.mp + "\\" + player.totalmp, 0.82, 0.95 );

    //health/magic bars
    canvas.SetPaintColor( "#ffff0000"  );    
    var hpsize = (player.hp/player.totalhp) * 0.6;
    canvas.DrawRectangle( 0.066, 0.9 - hpsize, 0.133 , 0.9);

    canvas.SetPaintColor( "#ff0000ff"  );
    var mpsize = (player.mp/player.totalmp) * 0.6;
    canvas.DrawRectangle( 0.866, 0.9 - mpsize, 0.933 , 0.9);
}



function drawChar() 
{   
    //Stick man
    //Head 
    canvas.SetPaintStyle( "Line" ); 
    canvas.SetPaintColor( "#ff000000" ); 
    canvas.DrawCircle( player.x, player.y, 0.02 );

    //Body
    canvas.SetLineWidth( 4.0 ); 
    canvas.DrawLine( player.x, player.y + 0.01, player.x, player.y + 0.05 ); 

    //Legs
    canvas.SetLineWidth( 2.5 ); 
    canvas.DrawLine( player.x, player.y + 0.05, player.x - 0.03, player.y + 0.08 ); 
    canvas.DrawLine( player.x, player.y + 0.05, player.x + 0.03, player.y + 0.08 ); 

    //Arms
    canvas.DrawLine( player.x - 0.04, player.y + 0.025, player.x + 0.04, player.y + 0.025 );
}



function drawEnemies(){
    canvas.SetPaintStyle( "Line" ); 
    canvas.SetPaintColor( "#000000" ); 
    for (var i = 0; i < game.enemies.length; i++) {
       if(game.enemies[i].isAlive){
           moveEnemyTowardsPlayer(game.enemies[i]);
           checkEnemy(game.enemies[i]);
           canvas.DrawCircle(game.enemies[i].x ,game.enemies[i].y ,0.01);     
       }
    }
}


function moveEnemyTowardsPlayer(enemy)
{
       if (game.isPaused) return;
       if (enemy.x < player.x) {
           enemy.x += enemy.speed;
       }
       if (enemy.x > player.x) {
           enemy.x -= enemy.speed;
       }
       if (enemy.y < player.y) {
           enemy.y += enemy.speed;
       }
       if (enemy.y > player.y) {
           enemy.y -= enemy.speed;
       }
}

function checkEnemy(enemy) 
{
       if (enemy.hp <= 0) return;
       if (enemy.x > player.x - 0.03 && enemy.x < player.x + 0.03 &&
           enemy.y > player.y - 0.02 && enemy.y < player.y + 0.08) {
               enemy.speed = 0;
               game.currentEnemy = enemy;     
               app.ShowPopup( game.currentEnemy.type + " Attacks!");
               if(Math.random() > 0.5) yourTurn = false;
               battleSetup();
               game.state = STATE.BATTLE;
       }
}







//BATTLE

//Hide moveButtons
//Show battleButtons
function battleSetup() {
                btnLeft.SetVisibility( "gone" );
                btnUp.SetVisibility( "gone" );
                btnDown.SetVisibility( "gone" );
                btnRight.SetVisibility( "gone" );
                btnAttack.SetVisibility( "show" );
                btnItem.SetVisibility( "show" );
                btnRun.SetVisibility( "show" );
                btnMagic.SetVisibility( "show" );
                canvas.SetLineWidth(10);
                canvas.SetPaintColor( "#ff777777"  );
                canvas.DrawLine(0, 1, 1, 1);
}

//Show moveButtons
//Hide battleButtons
function battleExit() {
               btnLeft.SetVisibility( "show" );
               btnUp.SetVisibility( "show" );
               btnDown.SetVisibility( "show" );
               btnRight.SetVisibility( "show" );
               btnAttack.SetVisibility( "gone" );
               btnItem.SetVisibility( "gone" );
               btnRun.SetVisibility( "gone" );
               btnMagic.SetVisibility( "gone" );
}

//Draw the Battle Screen
function drawBattleScreen()
{
    //Draw Enemy Stats
    canvas.SetLineWidth(1);
    canvas.SetTextSize( 9 );
    canvas.SetPaintColor( "#ff000000"  );
    canvas.DrawText( "" + game.currentEnemy.type + 
        "  HP: " + game.currentEnemy.hp + "\\" + game.currentEnemy.totalhp, 0.04, 0.07 );
    //Lines under enemy stats
    canvas.SetLineWidth(2.5);
    canvas.SetPaintColor( "#ff000000"  );
    canvas.DrawLine(0, 0.09, 0.25, 0.09);
    canvas.SetLineWidth(2.0);
    canvas.DrawLine(0, 0.10, 0.20, 0.10);
    canvas.SetLineWidth(1.5);
    canvas.DrawLine(0, 0.11, 0.15, 0.11);
    canvas.SetLineWidth(1.0);
    canvas.DrawLine(0, 0.12, 0.10, 0.12);
    canvas.SetLineWidth(0.5);
    canvas.DrawLine(0, 0.13, 0.05, 0.13);

    //Draw Player Stats
    canvas.SetLineWidth(1);
    canvas.SetTextSize( 9 );
    canvas.SetPaintColor( "#ff000000"  );
    canvas.DrawText( "HP: " + player.hp + "\\" + player.totalhp, 0.7, 0.87 );
    canvas.DrawText( "MP: " + player.mp + "\\" + player.totalmp, 0.7, 0.93 );

    //Draw Enemy
    //Head
    canvas.SetLineWidth(5);
    canvas.SetPaintColor( "#ff884400"  );
    canvas.DrawCircle( 0.7, 0.25, 0.2 );
    //Eyes
    canvas.SetPaintColor( "#ff222200"  );
    canvas.SetLineWidth(7);
    canvas.DrawLine( 0.55, 0.2, 0.64, 0.24);
    canvas.DrawLine( 0.79, 0.2, 0.70, 0.24);
    //Mouth
    canvas.SetPaintColor( "#ff000000"  );
    canvas.SetLineWidth(7);
    canvas.DrawLine( 0.59, 0.31, 0.75, 0.31);
    canvas.DrawLine( 0.61, 0.32, 0.73, 0.32);

    //Draw Player
    //Head
    canvas.SetLineWidth(10);
    canvas.SetPaintColor( "#ff000000"  );
    canvas.DrawCircle( 0, 0.5, 0.25 );
    //Body
    canvas.SetLineWidth(20);
    canvas.DrawLine(0, 0.65, 0, 1);
    //Arm
    canvas.DrawLine(0, 0.8, 0.4, 0.8);
    //Sword
    canvas.SetLineWidth(12);
    canvas.DrawLine(0.35, 0.88, 0.5, 0.5);
    canvas.SetLineWidth(7);
    canvas.DrawLine(0.3, 0.73, 0.5, 0.78);

    //BattleText
    canvas.SetLineWidth(1);
    canvas.DrawText(ui.battleText, 0.6, 0.7);

    showOrHideButtons();
}

function showOrHideButtons() {
    if(player.yourTurn) {
        btnAttack.SetVisibility("Show");
        btnItem.SetVisibility("Show");
        btnRun.SetVisibility("Show");
        btnMagic.SetVisibility("Show");
    }
    else {
        btnAttack.SetVisibility("Hide");
        btnItem.SetVisibility("Hide");
        btnRun.SetVisibility("Hide");
        btnMagic.SetVisibility("Hide");
    }
}



function youAttack(){
  if(player.hp <= 0) return;
  var tempRandom = (Math.random() > 0.3);
  app.ShowPopup( "str:" + player.strength + tempRandom);
  if(tempRandom) {  
      game.currentEnemy.hp -= player.strength;
      ui.battleText += "Hit for " + player.strength;      
   } else {
      ui.battleText += "You missed";      
   }
   checkEnemyDeath();
}

function enemyAttack(){ 
   if(game.currentEnemy.hp <= 0) return;
   if(Math.random() > 0.5) {  
      player.hp -= Math.floor(game.currentEnemy.str);
   } 
   checkPlayerDeath();

}

function checkEnemyDeath() {
    if(game.currentEnemy.hp <= 0) {
        game.currentEnemy.isAlive == false;
        player.exp += game.currentEnemy.exp;
        ui.battleText = "You defeated the " + game.currentEnemy.type + "! " +
                      "You gained " + game.currentEnemy.exp + " exp.";
        player.y += 0.01;
        battleExit();
        game.currentEnemy.x = 1000;
        game.state = STATE.WORLDMAP;
        areAllEnemiesDead();
    }
}

function areAllEnemiesDead(){
   var allDead = true;
   for (var i = 0; i < game.enemies.length; i++) {
       if(game.enemies[i].hp > 0){
           allDead = false;     
       }
    }
    if (allDead) {
       goToNextLevel();
    }
}

function checkPlayerDeath() {
    if(player.hp <= 0) {
        player.isAlive == false;
        player.hp = 0;
        app.ShowPopup( "Died on level " + game.level );
        btnStart.SetVisibility("gone");
        btnLeft.SetVisibility( "gone" );
        btnUp.SetVisibility( "gone" );
        btnDown.SetVisibility( "gone" );
        btnRight.SetVisibility( "gone" );
        btnAttack.SetVisibility( "gone" );
        btnItem.SetVisibility( "gone" );
        btnRun.SetVisibility( "gone" );
        btnMagic.SetVisibility( "gone" );
        btnStatus.SetVisibility( "gone" );
        canvas.SetBackColor( "#000000"  );
        drawFrame();
    }
}

Thanks!


Solution

  • I'm afraid that Sebastien is correct. The DrawText method in AndroidScript internally calls the standard Android SDK Canvas.DrawText() method, which does not support multi-line output (perhaps for performance reasons).

    You can see this from other people's questions about Android here:-

    Draw multi-line text to Canvas

    But you could try writing your own little Multi-line output function by splitting the string with the JavaScript split() method :)

    I like your app by the way... it looks fun!